67 parent::__construct(
'Allpages' );
70 $this->dbProvider = $dbProvider ?? $services->getConnectionProvider();
71 $this->searchEngineFactory = $searchEngineFactory ?? $services->getSearchEngineFactory();
72 $this->pageStore = $pageStore ?? $services->getPageStore();
86 $out->getMetadata()->setPreventClickjacking(
false );
89 $from = $request->getVal(
'from',
null );
90 $to = $request->getVal(
'to',
null );
91 $namespace = $request->getInt(
'namespace' );
96 $hideredirects = $request->getBool(
'hideredirects',
false ) && !$miserMode;
98 $namespaces = $this->
getLanguage()->getNamespaces();
100 $out->setPageTitleMsg(
101 ( $namespace > 0 && array_key_exists( $namespace, $namespaces ) ) ?
102 $this->
msg(
'allinnamespace' )->plaintextParams( str_replace(
'_',
' ', $namespaces[$namespace] ) ) :
103 $this->
msg(
'allarticles' )
105 $out->addModuleStyles(
'mediawiki.special' );
107 if ( $par !==
null ) {
108 $this->showChunk( $namespace, $par, $to, $hideredirects );
109 } elseif ( $from !==
null && $to ===
null ) {
110 $this->showChunk( $namespace, $from, $to, $hideredirects );
112 $this->showToplevel( $namespace, $from, $to, $hideredirects );
125 $from =
'', $to =
'', $hideRedirects =
false
134 'label-message' =>
'allpagesfrom',
135 'default' => str_replace(
'_',
' ', $from ),
142 'label-message' =>
'allpagesto',
143 'default' => str_replace(
'_',
' ', $to ),
146 'type' =>
'namespaceselect',
147 'name' =>
'namespace',
149 'label-message' =>
'namespace',
151 'default' => $namespace,
155 'name' =>
'hideredirects',
156 'id' =>
'hidredirects',
157 'label-message' =>
'allpages-hide-redirects',
158 'value' => $hideRedirects,
163 unset( $formDescriptor[
'hideredirects'] );
166 $htmlForm = HTMLForm::factory(
'ooui', $formDescriptor, $this->
getContext() );
170 ->setWrapperLegendMsg(
'allpages' )
171 ->setSubmitTextMsg(
'allpagessubmit' )
173 ->displayForm(
false );
182 private function showToplevel(
183 $namespace =
NS_MAIN, $from =
null, $to =
null, $hideredirects =
false
185 $from = $from ? Title::makeTitleSafe( $namespace, $from ) : null;
186 $to = $to ? Title::makeTitleSafe( $namespace, $to ) : null;
187 $from = ( $from && $from->isLocal() ) ? $from->getDBkey() :
null;
188 $to = ( $to && $to->isLocal() ) ? $to->getDBkey() :
null;
190 $this->showChunk( $namespace, $from, $to, $hideredirects );
199 private function showChunk(
200 $namespace =
NS_MAIN, $from =
null, $to =
null, $hideredirects =
false
206 $namespaces = $this->
getContext()->getLanguage()->getNamespaces();
210 if ( !$fromList || !$toList ) {
211 $out = $this->
msg(
'allpagesbadtitle' )->parseAsBlock();
212 } elseif ( !array_key_exists( $namespace, $namespaces ) ) {
214 $out = $this->
msg(
'allpages-bad-ns', $namespace )->parse();
217 [ $namespace, $fromKey, $from ] = $fromList;
218 [ , $toKey, $to ] = $toList;
220 $dbr = $this->dbProvider->getReplicaDatabase();
221 $filterConds = [
'page_namespace' => $namespace ];
222 if ( $hideredirects ) {
223 $filterConds[
'page_is_redirect'] = 0;
226 $conds = $filterConds;
227 $conds[] = $dbr->expr(
'page_title',
'>=', $fromKey );
228 if ( $toKey !==
"" ) {
229 $conds[] = $dbr->expr(
'page_title',
'<=', $toKey );
232 $res = $this->pageStore->newSelectQueryBuilder()
234 ->caller( __METHOD__ )
235 ->orderBy(
'page_title' )
236 ->limit( $this->maxPerPage + 1 )
237 ->useIndex(
'page_name_title' )
238 ->fetchPageRecords();
244 $pages = iterator_to_array( $res );
247 if ( count( $pages ) > 0 ) {
248 $out = Html::openElement(
'ul', [
'class' =>
'mw-allpages-chunk' ] );
250 while ( $n < $this->maxPerPage && $n < count( $pages ) ) {
252 $attributes = $page->isRedirect() ? [
'class' =>
'allpagesredirect' ] : [];
254 $out .= Html::rawElement(
'li', $attributes, $linkRenderer->makeKnownLink( $page ) ) .
"\n";
257 $out .= Html::closeElement(
'ul' );
259 if ( count( $pages ) > 2 ) {
262 $out = Html::rawElement(
'div', [
'class' =>
'mw-allpages-body' ], $out );
268 if ( $fromKey !==
'' && !$this->
including() ) {
269 # Get the first title from previous chunk
270 $prevConds = $filterConds;
271 $prevConds[] = $dbr->expr(
'page_title',
'<', $fromKey );
272 $prevKey = $dbr->newSelectQueryBuilder()
273 ->select(
'page_title' )
275 ->where( $prevConds )
276 ->orderBy(
'page_title', SelectQueryBuilder::SORT_DESC )
277 ->offset( $this->maxPerPage - 1 )
278 ->caller( __METHOD__ )->fetchField();
280 if ( $prevKey ===
false ) {
281 # The previous chunk is not complete, need to link to the very first title
282 # available in the database
283 $prevKey = $dbr->newSelectQueryBuilder()
284 ->select(
'page_title' )
286 ->where( $prevConds )
287 ->orderBy(
'page_title' )
288 ->caller( __METHOD__ )->fetchField();
291 if ( $prevKey !==
false ) {
292 $prevTitle = Title::makeTitle( $namespace, $prevKey );
298 $output->addHTML( $out );
308 $query = [
'from' => $prevTitle->getText() ];
311 $query[
'namespace'] = $namespace;
314 if ( $hideredirects ) {
315 $query[
'hideredirects'] = $hideredirects;
318 $navLinks[] = $linkRenderer->makeKnownLink(
320 $this->
msg(
'prevpage', $prevTitle->getText() )->text(),
328 if ( $n === $this->maxPerPage && isset( $pages[$n] ) ) {
329 # $t is the first link of the next chunk
330 $t = TitleValue::newFromPage( $pages[$n] );
331 $query = [
'from' =>
$t->getText() ];
334 $query[
'namespace'] = $namespace;
337 if ( $hideredirects ) {
338 $query[
'hideredirects'] = $hideredirects;
341 $navLinks[] = $linkRenderer->makeKnownLink(
343 $this->
msg(
'nextpage',
$t->getText() )->text(),
349 $this->
outputHTMLForm( $namespace, $from ??
'', $to ??
'', $hideredirects );
351 if ( count( $navLinks ) ) {
353 $pagination = Html::rawElement(
'div',
354 [
'class' =>
'mw-allpages-nav' ],
358 $output->addHTML( $pagination );
362 $output->addHTML( $out );
372 # shortcut for common case
373 return [ $ns,
'',
'' ];
376 $t = Title::makeTitleSafe( $ns, $text );
377 if ( $t && $t->isLocal() ) {
378 return [ $t->getNamespace(), $t->getDBkey(), $t->getText() ];
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(),
'',
'' ];
402 return $this->
prefixSearchString( $search, $limit, $offset, $this->searchEngineFactory );