MediaWiki  master
SpecialAllPages.php
Go to the documentation of this file.
1 <?php
31 
37  protected $maxPerPage = 345;
38 
44  protected $nsfromMsg = 'allpagesfrom';
45 
49  function __construct( $name = 'Allpages' ) {
50  parent::__construct( $name );
51  }
52 
58  function execute( $par ) {
59  $request = $this->getRequest();
60  $out = $this->getOutput();
61 
62  $this->setHeaders();
63  $this->outputHeader();
64  $out->allowClickjacking();
65 
66  # GET values
67  $from = $request->getVal( 'from', null );
68  $to = $request->getVal( 'to', null );
69  $namespace = $request->getInt( 'namespace' );
70 
71  $miserMode = (bool)$this->getConfig()->get( 'MiserMode' );
72 
73  // Redirects filter is disabled in MiserMode
74  $hideredirects = $request->getBool( 'hideredirects', false ) && !$miserMode;
75 
76  $namespaces = $this->getLanguage()->getNamespaces();
77 
78  $out->setPageTitle(
79  ( $namespace > 0 && array_key_exists( $namespace, $namespaces ) ) ?
80  $this->msg( 'allinnamespace', str_replace( '_', ' ', $namespaces[$namespace] ) ) :
81  $this->msg( 'allarticles' )
82  );
83  $out->addModuleStyles( 'mediawiki.special' );
84 
85  if ( $par !== null ) {
86  $this->showChunk( $namespace, $par, $to, $hideredirects );
87  } elseif ( $from !== null && $to === null ) {
88  $this->showChunk( $namespace, $from, $to, $hideredirects );
89  } else {
90  $this->showToplevel( $namespace, $from, $to, $hideredirects );
91  }
92  }
93 
102  protected function outputHTMLForm( $namespace = NS_MAIN,
103  $from = '', $to = '', $hideRedirects = false
104  ) {
105  $miserMode = (bool)$this->getConfig()->get( 'MiserMode' );
106  $formDescriptor = [
107  'from' => [
108  'type' => 'text',
109  'name' => 'from',
110  'id' => 'nsfrom',
111  'size' => 30,
112  'label-message' => 'allpagesfrom',
113  'default' => str_replace( '_', ' ', $from ),
114  ],
115  'to' => [
116  'type' => 'text',
117  'name' => 'to',
118  'id' => 'nsto',
119  'size' => 30,
120  'label-message' => 'allpagesto',
121  'default' => str_replace( '_', ' ', $to ),
122  ],
123  'namespace' => [
124  'type' => 'namespaceselect',
125  'name' => 'namespace',
126  'id' => 'namespace',
127  'label-message' => 'namespace',
128  'all' => null,
129  'default' => $namespace,
130  ],
131  'hideredirects' => [
132  'type' => 'check',
133  'name' => 'hideredirects',
134  'id' => 'hidredirects',
135  'label-message' => 'allpages-hide-redirects',
136  'value' => $hideRedirects,
137  ],
138  ];
139 
140  if ( $miserMode ) {
141  unset( $formDescriptor['hideredirects'] );
142  }
143 
144  $context = new DerivativeContext( $this->getContext() );
145  $context->setTitle( $this->getPageTitle() ); // Remove subpage
146  $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $context );
147  $htmlForm
148  ->setMethod( 'get' )
149  ->setWrapperLegendMsg( 'allpages' )
150  ->setSubmitTextMsg( 'allpagessubmit' )
151  ->prepareForm()
152  ->displayForm( false );
153  }
154 
161  function showToplevel( $namespace = NS_MAIN, $from = '', $to = '', $hideredirects = false ) {
162  $from = Title::makeTitleSafe( $namespace, $from );
163  $to = Title::makeTitleSafe( $namespace, $to );
164  $from = ( $from && $from->isLocal() ) ? $from->getDBkey() : null;
165  $to = ( $to && $to->isLocal() ) ? $to->getDBkey() : null;
166 
167  $this->showChunk( $namespace, $from, $to, $hideredirects );
168  }
169 
176  function showChunk( $namespace = NS_MAIN, $from = false, $to = false, $hideredirects = false ) {
177  $output = $this->getOutput();
178 
179  $fromList = $this->getNamespaceKeyAndText( $namespace, $from );
180  $toList = $this->getNamespaceKeyAndText( $namespace, $to );
181  $namespaces = $this->getContext()->getLanguage()->getNamespaces();
182  $n = 0;
183  $prevTitle = null;
184 
185  if ( !$fromList || !$toList ) {
186  $out = $this->msg( 'allpagesbadtitle' )->parseAsBlock();
187  } elseif ( !array_key_exists( $namespace, $namespaces ) ) {
188  // Show errormessage and reset to NS_MAIN
189  $out = $this->msg( 'allpages-bad-ns', $namespace )->parse();
190  $namespace = NS_MAIN;
191  } else {
192  list( $namespace, $fromKey, $from ) = $fromList;
193  list( , $toKey, $to ) = $toList;
194 
195  $dbr = wfGetDB( DB_REPLICA );
196  $filterConds = [ 'page_namespace' => $namespace ];
197  if ( $hideredirects ) {
198  $filterConds['page_is_redirect'] = 0;
199  }
200 
201  $conds = $filterConds;
202  $conds[] = 'page_title >= ' . $dbr->addQuotes( $fromKey );
203  if ( $toKey !== "" ) {
204  $conds[] = 'page_title <= ' . $dbr->addQuotes( $toKey );
205  }
206 
207  $res = $dbr->select( 'page',
208  [ 'page_namespace', 'page_title', 'page_is_redirect', 'page_id' ],
209  $conds,
210  __METHOD__,
211  [
212  'ORDER BY' => 'page_title',
213  'LIMIT' => $this->maxPerPage + 1,
214  'USE INDEX' => 'name_title',
215  ]
216  );
217 
218  $linkRenderer = $this->getLinkRenderer();
219  if ( $res->numRows() > 0 ) {
220  $out = Html::openElement( 'ul', [ 'class' => 'mw-allpages-chunk' ] );
221 
222  while ( ( $n < $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) {
223  $t = Title::newFromRow( $s );
224  if ( $t ) {
225  $out .= '<li' .
226  ( $s->page_is_redirect ? ' class="allpagesredirect"' : '' ) .
227  '>' .
228  $linkRenderer->makeLink( $t ) .
229  "</li>\n";
230  } else {
231  $out .= '<li>[[' . htmlspecialchars( $s->page_title ) . "]]</li>\n";
232  }
233  $n++;
234  }
235  $out .= Html::closeElement( 'ul' );
236 
237  if ( $res->numRows() > 2 ) {
238  // Only apply CSS column styles if there's more than 2 entries.
239  // Otherwise, rendering is broken as "mw-allpages-body"'s CSS column count is 3.
240  $out = Html::rawElement( 'div', [ 'class' => 'mw-allpages-body' ], $out );
241  }
242  } else {
243  $out = '';
244  }
245 
246  if ( $fromKey !== '' && !$this->including() ) {
247  # Get the first title from previous chunk
248  $prevConds = $filterConds;
249  $prevConds[] = 'page_title < ' . $dbr->addQuotes( $fromKey );
250  $prevKey = $dbr->selectField(
251  'page',
252  'page_title',
253  $prevConds,
254  __METHOD__,
255  [ 'ORDER BY' => 'page_title DESC', 'OFFSET' => $this->maxPerPage - 1 ]
256  );
257 
258  if ( $prevKey === false ) {
259  # The previous chunk is not complete, need to link to the very first title
260  # available in the database
261  $prevKey = $dbr->selectField(
262  'page',
263  'page_title',
264  $prevConds,
265  __METHOD__,
266  [ 'ORDER BY' => 'page_title' ]
267  );
268  }
269 
270  if ( $prevKey !== false ) {
271  $prevTitle = Title::makeTitle( $namespace, $prevKey );
272  }
273  }
274  }
275 
276  if ( $this->including() ) {
277  $output->addHTML( $out );
278  return;
279  }
280 
281  $navLinks = [];
282  $self = $this->getPageTitle();
283 
284  $linkRenderer = $this->getLinkRenderer();
285  // Generate a "previous page" link if needed
286  if ( $prevTitle ) {
287  $query = [ 'from' => $prevTitle->getText() ];
288 
289  if ( $namespace ) {
290  $query['namespace'] = $namespace;
291  }
292 
293  if ( $hideredirects ) {
294  $query['hideredirects'] = $hideredirects;
295  }
296 
297  $navLinks[] = $linkRenderer->makeKnownLink(
298  $self,
299  $this->msg( 'prevpage', $prevTitle->getText() )->text(),
300  [],
301  $query
302  );
303 
304  }
305 
306  // Generate a "next page" link if needed
307  if ( $n == $this->maxPerPage && $s = $res->fetchObject() ) {
308  # $s is the first link of the next chunk
309  $t = Title::makeTitle( $namespace, $s->page_title );
310  $query = [ 'from' => $t->getText() ];
311 
312  if ( $namespace ) {
313  $query['namespace'] = $namespace;
314  }
315 
316  if ( $hideredirects ) {
317  $query['hideredirects'] = $hideredirects;
318  }
319 
320  $navLinks[] = $linkRenderer->makeKnownLink(
321  $self,
322  $this->msg( 'nextpage', $t->getText() )->text(),
323  [],
324  $query
325  );
326  }
327 
328  $this->outputHTMLForm( $namespace, $from, $to, $hideredirects );
329 
330  if ( count( $navLinks ) ) {
331  // Add pagination links
332  $pagination = Html::rawElement( 'div',
333  [ 'class' => 'mw-allpages-nav' ],
334  $this->getLanguage()->pipeList( $navLinks )
335  );
336 
337  $output->addHTML( $pagination );
338  $out .= Html::element( 'hr' ) . $pagination; // Footer
339  }
340 
341  $output->addHTML( $out );
342  }
343 
349  protected function getNamespaceKeyAndText( $ns, $text ) {
350  if ( $text == '' ) {
351  # shortcut for common case
352  return [ $ns, '', '' ];
353  }
354 
355  $t = Title::makeTitleSafe( $ns, $text );
356  if ( $t && $t->isLocal() ) {
357  return [ $t->getNamespace(), $t->getDBkey(), $t->getText() ];
358  } elseif ( $t ) {
359  return null;
360  }
361 
362  # try again, in case the problem was an empty pagename
363  $text = preg_replace( '/(#|$)/', 'X$1', $text );
364  $t = Title::makeTitleSafe( $ns, $text );
365  if ( $t && $t->isLocal() ) {
366  return [ $t->getNamespace(), '', '' ];
367  } else {
368  return null;
369  }
370  }
371 
380  public function prefixSearchSubpages( $search, $limit, $offset ) {
381  return $this->prefixSearchString( $search, $limit, $offset );
382  }
383 
384  protected function getGroupName() {
385  return 'pages';
386  }
387 }
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:231
$context
Definition: load.php:40
getContext()
Gets the context this SpecialPage is executed in.
const NS_MAIN
Definition: Defines.php:60
including( $x=null)
Whether the special page is being evaluated via transclusion.
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing &#39;/&#39;...
Definition: Html.php:251
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:209
An IContextSource implementation which will inherit context from another source but allow individual ...
Implements Special:Allpages.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
outputHTMLForm( $namespace=NS_MAIN, $from='', $to='', $hideRedirects=false)
Outputs the HTMLForm used on this page.
getOutput()
Get the OutputPage being used for this instance.
static newFromRow( $row)
Make a Title object from a DB row.
Definition: Title.php:516
getNamespaceKeyAndText( $ns, $text)
__construct( $name='Allpages')
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
static factory( $displayFormat,... $arguments)
Construct a HTMLForm object for given display type.
Definition: HTMLForm.php:307
prefixSearchString( $search, $limit, $offset)
Perform a regular substring search for prefixSearchSubpages.
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
Shortcut to construct an includable special page.
showChunk( $namespace=NS_MAIN, $from=false, $to=false, $hideredirects=false)
$self
static closeElement( $element)
Returns "</$element>".
Definition: Html.php:315
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes! ...
int $maxPerPage
Maximum number of pages to show on single subpage.
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:610
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:584
getConfig()
Shortcut to get main config object.
getLanguage()
Shortcut to get user&#39;s language.
string $nsfromMsg
Determines, which message describes the input field &#39;nsfrom&#39;.
const DB_REPLICA
Definition: defines.php:25
showToplevel( $namespace=NS_MAIN, $from='', $to='', $hideredirects=false)
getRequest()
Get the WebRequest being used for this instance.
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
getPageTitle( $subpage=false)
Get a self-referential title object.
execute( $par)
Entry point : initialise variables and call subfunctions.
MediaWiki Linker LinkRenderer null $linkRenderer
Definition: SpecialPage.php:67