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 
228  $res = $dbr->select( 'page',
229  [ 'page_namespace', 'page_title', 'page_is_redirect', 'page_id' ],
230  $conds,
231  __METHOD__,
232  [
233  'ORDER BY' => 'page_title',
234  'LIMIT' => $this->maxPerPage + 1,
235  'USE INDEX' => 'name_title',
236  ]
237  );
238 
239  $linkRenderer = $this->getLinkRenderer();
240  if ( $res->numRows() > 0 ) {
241  $out = Html::openElement( 'ul', [ 'class' => 'mw-allpages-chunk' ] );
242 
243  while ( ( $n < $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) {
244  $t = Title::newFromRow( $s );
245  if ( $t ) {
246  $out .= '<li' .
247  ( $s->page_is_redirect ? ' class="allpagesredirect"' : '' ) .
248  '>' .
249  $linkRenderer->makeLink( $t ) .
250  "</li>\n";
251  } else {
252  $out .= '<li>[[' . htmlspecialchars( $s->page_title ) . "]]</li>\n";
253  }
254  $n++;
255  }
256  $out .= Html::closeElement( 'ul' );
257 
258  if ( $res->numRows() > 2 ) {
259  // Only apply CSS column styles if there's more than 2 entries.
260  // Otherwise, rendering is broken as "mw-allpages-body"'s CSS column count is 3.
261  $out = Html::rawElement( 'div', [ 'class' => 'mw-allpages-body' ], $out );
262  }
263  } else {
264  $out = '';
265  }
266 
267  if ( $fromKey !== '' && !$this->including() ) {
268  # Get the first title from previous chunk
269  $prevConds = $filterConds;
270  $prevConds[] = 'page_title < ' . $dbr->addQuotes( $fromKey );
271  $prevKey = $dbr->selectField(
272  'page',
273  'page_title',
274  $prevConds,
275  __METHOD__,
276  [ 'ORDER BY' => 'page_title DESC', 'OFFSET' => $this->maxPerPage - 1 ]
277  );
278 
279  if ( $prevKey === false ) {
280  # The previous chunk is not complete, need to link to the very first title
281  # available in the database
282  $prevKey = $dbr->selectField(
283  'page',
284  'page_title',
285  $prevConds,
286  __METHOD__,
287  [ 'ORDER BY' => 'page_title' ]
288  );
289  }
290 
291  if ( $prevKey !== false ) {
292  $prevTitle = Title::makeTitle( $namespace, $prevKey );
293  }
294  }
295  }
296 
297  if ( $this->including() ) {
298  $output->addHTML( $out );
299  return;
300  }
301 
302  $navLinks = [];
303  $self = $this->getPageTitle();
304 
305  $linkRenderer = $this->getLinkRenderer();
306  // Generate a "previous page" link if needed
307  if ( $prevTitle ) {
308  $query = [ 'from' => $prevTitle->getText() ];
309 
310  if ( $namespace ) {
311  $query['namespace'] = $namespace;
312  }
313 
314  if ( $hideredirects ) {
315  $query['hideredirects'] = $hideredirects;
316  }
317 
318  $navLinks[] = $linkRenderer->makeKnownLink(
319  $self,
320  $this->msg( 'prevpage', $prevTitle->getText() )->text(),
321  [],
322  $query
323  );
324 
325  }
326 
327  // Generate a "next page" link if needed
328  if ( $n == $this->maxPerPage && $s = $res->fetchObject() ) {
329  # $s is the first link of the next chunk
330  $t = Title::makeTitle( $namespace, $s->page_title );
331  $query = [ 'from' => $t->getText() ];
332 
333  if ( $namespace ) {
334  $query['namespace'] = $namespace;
335  }
336 
337  if ( $hideredirects ) {
338  $query['hideredirects'] = $hideredirects;
339  }
340 
341  $navLinks[] = $linkRenderer->makeKnownLink(
342  $self,
343  $this->msg( 'nextpage', $t->getText() )->text(),
344  [],
345  $query
346  );
347  }
348 
349  $this->outputHTMLForm( $namespace, $from, $to, $hideredirects );
350 
351  if ( count( $navLinks ) ) {
352  // Add pagination links
353  $pagination = Html::rawElement( 'div',
354  [ 'class' => 'mw-allpages-nav' ],
355  $this->getLanguage()->pipeList( $navLinks )
356  );
357 
358  $output->addHTML( $pagination );
359  $out .= Html::element( 'hr' ) . $pagination; // Footer
360  }
361 
362  $output->addHTML( $out );
363  }
364 
370  protected function getNamespaceKeyAndText( $ns, $text ) {
371  if ( $text == '' ) {
372  # shortcut for common case
373  return [ $ns, '', '' ];
374  }
375 
376  $t = Title::makeTitleSafe( $ns, $text );
377  if ( $t && $t->isLocal() ) {
378  return [ $t->getNamespace(), $t->getDBkey(), $t->getText() ];
379  } elseif ( $t ) {
380  return null;
381  }
382 
383  # try again, in case the problem was an empty pagename
384  $text = preg_replace( '/(#|$)/', 'X$1', $text );
385  $t = Title::makeTitleSafe( $ns, $text );
386  if ( $t && $t->isLocal() ) {
387  return [ $t->getNamespace(), '', '' ];
388  } else {
389  return null;
390  }
391  }
392 
401  public function prefixSearchSubpages( $search, $limit, $offset ) {
402  return $this->prefixSearchString( $search, $limit, $offset, $this->searchEngineFactory );
403  }
404 
405  protected function getGroupName() {
406  return 'pages';
407  }
408 }
SpecialAllPages\getGroupName
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
Definition: SpecialAllPages.php:405
SpecialPage\$linkRenderer
LinkRenderer null $linkRenderer
Definition: SpecialPage.php:79
SpecialPage\getPageTitle
getPageTitle( $subpage=false)
Get a self-referential title object.
Definition: SpecialPage.php:742
SpecialPage\msg
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
Definition: SpecialPage.php:900
SpecialPage\getOutput
getOutput()
Get the OutputPage being used for this instance.
Definition: SpecialPage.php:788
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:166
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:13
$s
$s
Definition: mergeMessageFileList.php:186
IncludableSpecialPage
Shortcut to construct an includable special page.
Definition: IncludableSpecialPage.php:29
SpecialPage\getLanguage
getLanguage()
Shortcut to get user's language.
Definition: SpecialPage.php:818
$res
$res
Definition: testCompression.php:57
NS_MAIN
const NS_MAIN
Definition: Defines.php:63
$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:575
Html\closeElement
static closeElement( $element)
Returns "</$element>".
Definition: Html.php:318
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:866
SpecialAllPages\$loadBalancer
ILoadBalancer $loadBalancer
Definition: SpecialAllPages.php:50
Title\newFromRow
static newFromRow( $row)
Make a Title object from a DB row.
Definition: Title.php:556
SpecialPage\setHeaders
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!...
Definition: SpecialPage.php:616
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:624
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
SpecialPage\getContext
getContext()
Gets the context this SpecialPage is executed in.
Definition: SpecialPage.php:762
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:650
SpecialAllPages\prefixSearchSubpages
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
Definition: SpecialAllPages.php:401
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:370
SpecialPage\getRequest
getRequest()
Get the WebRequest being used for this instance.
Definition: SpecialPage.php:778
SpecialPage\getLinkRenderer
getLinkRenderer()
Definition: SpecialPage.php:1016
$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:254
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:212
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:234
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:321
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:707
SpecialPage\including
including( $x=null)
Whether the special page is being evaluated via transclusion.
Definition: SpecialPage.php:265
Wikimedia\Rdbms\ILoadBalancer
Database cluster connection, tracking, load balancing, and transaction manager interface.
Definition: ILoadBalancer.php:81