55 private $loadBalancer;
58 private $searchEngineFactory;
68 parent::__construct(
'Allpages' );
70 $services = MediaWikiServices::getInstance();
71 $this->loadBalancer = $loadBalancer ?? $services->getDBLoadBalancer();
72 $this->searchEngineFactory = $searchEngineFactory ?? $services->getSearchEngineFactory();
73 $this->pageStore = $pageStore ?? $services->getPageStore();
87 $out->setPreventClickjacking(
false );
90 $from = $request->getVal(
'from',
null );
91 $to = $request->getVal(
'to',
null );
92 $namespace = $request->getInt(
'namespace' );
94 $miserMode = (bool)$this->
getConfig()->get( MainConfigNames::MiserMode );
97 $hideredirects = $request->getBool(
'hideredirects',
false ) && !$miserMode;
99 $namespaces = $this->
getLanguage()->getNamespaces();
102 ( $namespace > 0 && array_key_exists( $namespace, $namespaces ) ) ?
103 $this->
msg(
'allinnamespace', str_replace(
'_',
' ', $namespaces[$namespace] ) ) :
104 $this->
msg(
'allarticles' )
106 $out->addModuleStyles(
'mediawiki.special' );
108 if ( $par !==
null ) {
109 $this->showChunk( $namespace, $par, $to, $hideredirects );
110 } elseif ( $from !==
null && $to ===
null ) {
111 $this->showChunk( $namespace, $from, $to, $hideredirects );
113 $this->showToplevel( $namespace, $from, $to, $hideredirects );
126 $from =
'', $to =
'', $hideRedirects =
false
128 $miserMode = (bool)$this->
getConfig()->get( MainConfigNames::MiserMode );
135 'label-message' =>
'allpagesfrom',
136 'default' => str_replace(
'_',
' ', $from ),
143 'label-message' =>
'allpagesto',
144 'default' => str_replace(
'_',
' ', $to ),
147 'type' =>
'namespaceselect',
148 'name' =>
'namespace',
150 'label-message' =>
'namespace',
152 'default' => $namespace,
156 'name' =>
'hideredirects',
157 'id' =>
'hidredirects',
158 'label-message' =>
'allpages-hide-redirects',
159 'value' => $hideRedirects,
164 unset( $formDescriptor[
'hideredirects'] );
167 $htmlForm = HTMLForm::factory(
'ooui', $formDescriptor, $this->
getContext() );
171 ->setWrapperLegendMsg(
'allpages' )
172 ->setSubmitTextMsg(
'allpagessubmit' )
174 ->displayForm(
false );
183 private function showToplevel(
184 $namespace =
NS_MAIN, $from =
null, $to =
null, $hideredirects =
false
186 $from = $from ? Title::makeTitleSafe( $namespace, $from ) : null;
187 $to = $to ? Title::makeTitleSafe( $namespace, $to ) : null;
188 $from = ( $from && $from->isLocal() ) ? $from->getDBkey() :
null;
189 $to = ( $to && $to->isLocal() ) ? $to->getDBkey() :
null;
191 $this->showChunk( $namespace, $from, $to, $hideredirects );
200 private function showChunk(
201 $namespace =
NS_MAIN, $from =
null, $to =
null, $hideredirects =
false
207 $namespaces = $this->
getContext()->getLanguage()->getNamespaces();
211 if ( !$fromList || !$toList ) {
212 $out = $this->
msg(
'allpagesbadtitle' )->parseAsBlock();
213 } elseif ( !array_key_exists( $namespace, $namespaces ) ) {
215 $out = $this->
msg(
'allpages-bad-ns', $namespace )->parse();
218 [ $namespace, $fromKey, $from ] = $fromList;
219 [ , $toKey, $to ] = $toList;
221 $dbr = $this->loadBalancer->getConnection( ILoadBalancer::DB_REPLICA );
222 $filterConds = [
'page_namespace' => $namespace ];
223 if ( $hideredirects ) {
224 $filterConds[
'page_is_redirect'] = 0;
227 $conds = $filterConds;
228 $conds[] =
'page_title >= ' .
$dbr->addQuotes( $fromKey );
229 if ( $toKey !==
"" ) {
230 $conds[] =
'page_title <= ' .
$dbr->addQuotes( $toKey );
233 $res = $this->pageStore->newSelectQueryBuilder()
235 ->caller( __METHOD__ )
236 ->orderBy(
'page_title' )
237 ->limit( $this->maxPerPage + 1 )
238 ->useIndex(
'page_name_title' )
239 ->fetchPageRecords();
245 $pages = iterator_to_array(
$res );
248 if ( count( $pages ) > 0 ) {
249 $out = Html::openElement(
'ul', [
'class' =>
'mw-allpages-chunk' ] );
251 while ( $n < $this->maxPerPage && $n < count( $pages ) ) {
253 $attributes = $page->isRedirect() ? [
'class' =>
'allpagesredirect' ] : [];
255 $out .= Html::rawElement(
'li', $attributes, $linkRenderer->makeKnownLink( $page ) ) .
"\n";
258 $out .= Html::closeElement(
'ul' );
260 if ( count( $pages ) > 2 ) {
263 $out = Html::rawElement(
'div', [
'class' =>
'mw-allpages-body' ], $out );
269 if ( $fromKey !==
'' && !$this->
including() ) {
270 # Get the first title from previous chunk
271 $prevConds = $filterConds;
272 $prevConds[] =
'page_title < ' .
$dbr->addQuotes( $fromKey );
273 $prevKey =
$dbr->selectField(
278 [
'ORDER BY' =>
'page_title DESC',
'OFFSET' => $this->maxPerPage - 1 ]
281 if ( $prevKey ===
false ) {
282 # The previous chunk is not complete, need to link to the very first title
283 # available in the database
284 $prevKey =
$dbr->selectField(
289 [
'ORDER BY' =>
'page_title' ]
293 if ( $prevKey !==
false ) {
294 $prevTitle = Title::makeTitle( $namespace, $prevKey );
300 $output->addHTML( $out );
310 $query = [
'from' => $prevTitle->getText() ];
313 $query[
'namespace'] = $namespace;
316 if ( $hideredirects ) {
317 $query[
'hideredirects'] = $hideredirects;
320 $navLinks[] = $linkRenderer->makeKnownLink(
322 $this->
msg(
'prevpage', $prevTitle->getText() )->text(),
330 if ( $n === $this->maxPerPage && isset( $pages[$n] ) ) {
331 # $t is the first link of the next chunk
333 $query = [
'from' =>
$t->getText() ];
336 $query[
'namespace'] = $namespace;
339 if ( $hideredirects ) {
340 $query[
'hideredirects'] = $hideredirects;
343 $navLinks[] = $linkRenderer->makeKnownLink(
345 $this->
msg(
'nextpage',
$t->getText() )->text(),
353 if ( count( $navLinks ) ) {
355 $pagination = Html::rawElement(
'div',
356 [
'class' =>
'mw-allpages-nav' ],
360 $output->addHTML( $pagination );
361 $out .= Html::element(
'hr' ) . $pagination;
364 $output->addHTML( $out );
374 # shortcut for common case
375 return [ $ns,
'',
'' ];
378 $t = Title::makeTitleSafe( $ns, $text );
379 if (
$t &&
$t->isLocal() ) {
380 return [
$t->getNamespace(),
$t->getDBkey(),
$t->getText() ];
385 # try again, in case the problem was an empty pagename
386 $text = preg_replace(
'/(#|$)/',
'X$1', $text );
387 $t = Title::makeTitleSafe( $ns, $text );
388 if (
$t &&
$t->isLocal() ) {
389 return [
$t->getNamespace(),
'',
'' ];
404 return $this->
prefixSearchString( $search, $limit, $offset, $this->searchEngineFactory );
Shortcut to construct an includable special page.
Implements Special:Allpages.
int $maxPerPage
Maximum number of pages to show on single subpage.
__construct(ILoadBalancer $loadBalancer=null, SearchEngineFactory $searchEngineFactory=null, PageStore $pageStore=null)
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
execute( $par)
Entry point : initialise variables and call subfunctions.
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
string $nsfromMsg
Determines, which message describes the input field 'nsfrom'.
outputHTMLForm( $namespace=NS_MAIN, $from='', $to='', $hideRedirects=false)
Outputs the HTMLForm used on this page.
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.
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.