70 parent::__construct(
'Allpages' );
73 $this->dbProvider = $dbProvider ?? $services->getDBLoadBalancerFactory();
74 $this->searchEngineFactory = $searchEngineFactory ?? $services->getSearchEngineFactory();
75 $this->pageStore = $pageStore ?? $services->getPageStore();
89 $out->setPreventClickjacking(
false );
92 $from = $request->getVal(
'from',
null );
93 $to = $request->getVal(
'to',
null );
94 $namespace = $request->getInt(
'namespace' );
99 $hideredirects = $request->getBool(
'hideredirects',
false ) && !$miserMode;
101 $namespaces = $this->
getLanguage()->getNamespaces();
103 $out->setPageTitleMsg(
104 ( $namespace > 0 && array_key_exists( $namespace, $namespaces ) ) ?
105 $this->
msg(
'allinnamespace' )->plaintextParams( str_replace(
'_',
' ', $namespaces[$namespace] ) ) :
106 $this->
msg(
'allarticles' )
108 $out->addModuleStyles(
'mediawiki.special' );
110 if ( $par !==
null ) {
111 $this->showChunk( $namespace, $par, $to, $hideredirects );
112 } elseif ( $from !==
null && $to ===
null ) {
113 $this->showChunk( $namespace, $from, $to, $hideredirects );
115 $this->showToplevel( $namespace, $from, $to, $hideredirects );
128 $from =
'', $to =
'', $hideRedirects =
false
137 'label-message' =>
'allpagesfrom',
138 'default' => str_replace(
'_',
' ', $from ),
145 'label-message' =>
'allpagesto',
146 'default' => str_replace(
'_',
' ', $to ),
149 'type' =>
'namespaceselect',
150 'name' =>
'namespace',
152 'label-message' =>
'namespace',
154 'default' => $namespace,
158 'name' =>
'hideredirects',
159 'id' =>
'hidredirects',
160 'label-message' =>
'allpages-hide-redirects',
161 'value' => $hideRedirects,
166 unset( $formDescriptor[
'hideredirects'] );
169 $htmlForm = HTMLForm::factory(
'ooui', $formDescriptor, $this->
getContext() );
173 ->setWrapperLegendMsg(
'allpages' )
174 ->setSubmitTextMsg(
'allpagessubmit' )
176 ->displayForm(
false );
185 private function showToplevel(
186 $namespace =
NS_MAIN, $from =
null, $to =
null, $hideredirects =
false
188 $from = $from ? Title::makeTitleSafe( $namespace, $from ) : null;
189 $to = $to ? Title::makeTitleSafe( $namespace, $to ) : null;
190 $from = ( $from && $from->isLocal() ) ? $from->getDBkey() :
null;
191 $to = ( $to && $to->isLocal() ) ? $to->getDBkey() :
null;
193 $this->showChunk( $namespace, $from, $to, $hideredirects );
202 private function showChunk(
203 $namespace =
NS_MAIN, $from =
null, $to =
null, $hideredirects =
false
209 $namespaces = $this->
getContext()->getLanguage()->getNamespaces();
213 if ( !$fromList || !$toList ) {
214 $out = $this->
msg(
'allpagesbadtitle' )->parseAsBlock();
215 } elseif ( !array_key_exists( $namespace, $namespaces ) ) {
217 $out = $this->
msg(
'allpages-bad-ns', $namespace )->parse();
220 [ $namespace, $fromKey, $from ] = $fromList;
221 [ , $toKey, $to ] = $toList;
223 $dbr = $this->dbProvider->getReplicaDatabase();
224 $filterConds = [
'page_namespace' => $namespace ];
225 if ( $hideredirects ) {
226 $filterConds[
'page_is_redirect'] = 0;
229 $conds = $filterConds;
230 $conds[] =
'page_title >= ' . $dbr->addQuotes( $fromKey );
231 if ( $toKey !==
"" ) {
232 $conds[] =
'page_title <= ' . $dbr->addQuotes( $toKey );
235 $res = $this->pageStore->newSelectQueryBuilder()
237 ->caller( __METHOD__ )
238 ->orderBy(
'page_title' )
239 ->limit( $this->maxPerPage + 1 )
240 ->useIndex(
'page_name_title' )
241 ->fetchPageRecords();
247 $pages = iterator_to_array( $res );
250 if ( count( $pages ) > 0 ) {
251 $out = Html::openElement(
'ul', [
'class' =>
'mw-allpages-chunk' ] );
253 while ( $n < $this->maxPerPage && $n < count( $pages ) ) {
255 $attributes = $page->isRedirect() ? [
'class' =>
'allpagesredirect' ] : [];
257 $out .= Html::rawElement(
'li', $attributes, $linkRenderer->makeKnownLink( $page ) ) .
"\n";
260 $out .= Html::closeElement(
'ul' );
262 if ( count( $pages ) > 2 ) {
265 $out = Html::rawElement(
'div', [
'class' =>
'mw-allpages-body' ], $out );
271 if ( $fromKey !==
'' && !$this->
including() ) {
272 # Get the first title from previous chunk
273 $prevConds = $filterConds;
274 $prevConds[] =
'page_title < ' . $dbr->addQuotes( $fromKey );
275 $prevKey = $dbr->newSelectQueryBuilder()
276 ->select(
'page_title' )
278 ->where( $prevConds )
279 ->orderBy(
'page_title', SelectQueryBuilder::SORT_DESC )
280 ->offset( $this->maxPerPage - 1 )
281 ->caller( __METHOD__ )->fetchField();
283 if ( $prevKey ===
false ) {
284 # The previous chunk is not complete, need to link to the very first title
285 # available in the database
286 $prevKey = $dbr->newSelectQueryBuilder()
287 ->select(
'page_title' )
289 ->where( $prevConds )
290 ->orderBy(
'page_title' )
291 ->caller( __METHOD__ )->fetchField();
294 if ( $prevKey !==
false ) {
295 $prevTitle = Title::makeTitle( $namespace, $prevKey );
301 $output->addHTML( $out );
311 $query = [
'from' => $prevTitle->getText() ];
314 $query[
'namespace'] = $namespace;
317 if ( $hideredirects ) {
318 $query[
'hideredirects'] = $hideredirects;
321 $navLinks[] = $linkRenderer->makeKnownLink(
323 $this->
msg(
'prevpage', $prevTitle->getText() )->text(),
331 if ( $n === $this->maxPerPage && isset( $pages[$n] ) ) {
332 # $t is the first link of the next chunk
333 $t = TitleValue::newFromPage( $pages[$n] );
334 $query = [
'from' =>
$t->getText() ];
337 $query[
'namespace'] = $namespace;
340 if ( $hideredirects ) {
341 $query[
'hideredirects'] = $hideredirects;
344 $navLinks[] = $linkRenderer->makeKnownLink(
346 $this->
msg(
'nextpage',
$t->getText() )->text(),
352 $this->
outputHTMLForm( $namespace, $from ??
'', $to ??
'', $hideredirects );
354 if ( count( $navLinks ) ) {
356 $pagination = Html::rawElement(
'div',
357 [
'class' =>
'mw-allpages-nav' ],
361 $output->addHTML( $pagination );
362 $out .= Html::element(
'hr' ) . $pagination;
365 $output->addHTML( $out );
375 # shortcut for common case
376 return [ $ns,
'',
'' ];
379 $t = Title::makeTitleSafe( $ns, $text );
380 if ( $t && $t->isLocal() ) {
381 return [ $t->getNamespace(), $t->getDBkey(), $t->getText() ];
386 # try again, in case the problem was an empty pagename
387 $text = preg_replace(
'/(#|$)/',
'X$1', $text );
388 $t = Title::makeTitleSafe( $ns, $text );
389 if ( $t && $t->isLocal() ) {
390 return [ $t->getNamespace(),
'',
'' ];
405 return $this->
prefixSearchString( $search, $limit, $offset, $this->searchEngineFactory );