MediaWiki 1.41.2
SpecialPrefixIndex.php
Go to the documentation of this file.
1<?php
24namespace MediaWiki\Specials;
25
27use HTMLForm;
28use LinkCache;
32
39
44 protected $stripPrefix = false;
45
46 protected $hideRedirects = false;
47
48 // Inherit $maxPerPage
49
50 private IConnectionProvider $dbProvider;
51 private LinkCache $linkCache;
52
57 public function __construct(
58 IConnectionProvider $dbProvider,
59 LinkCache $linkCache
60 ) {
61 parent::__construct( $dbProvider );
62 $this->mName = 'Prefixindex';
63 $this->dbProvider = $dbProvider;
64 $this->linkCache = $linkCache;
65 }
66
71 public function execute( $par ) {
72 $this->setHeaders();
73 $this->outputHeader();
74
75 $out = $this->getOutput();
76 $out->addModuleStyles( 'mediawiki.special' );
77
78 # GET values
79 $request = $this->getRequest();
80 $from = $request->getVal( 'from', '' );
81 $prefix = $request->getVal( 'prefix', '' );
82 $ns = $request->getIntOrNull( 'namespace' );
83 $namespace = (int)$ns; // if no namespace given, use 0 (NS_MAIN).
84 $this->hideRedirects = $request->getBool( 'hideredirects', $this->hideRedirects );
85 $this->stripPrefix = $request->getBool( 'stripprefix', $this->stripPrefix );
86
87 $namespaces = $this->getContentLanguage()->getNamespaces();
88 $out->setPageTitleMsg(
89 ( $namespace > 0 && array_key_exists( $namespace, $namespaces ) )
90 ? $this->msg( 'prefixindex-namespace' )->plaintextParams(
91 str_replace( '_', ' ', $namespaces[$namespace] )
92 )
93 : $this->msg( 'prefixindex' )
94 );
95
96 $showme = '';
97 if ( $par !== null ) {
98 $showme = $par;
99 } elseif ( $prefix != '' ) {
100 $showme = $prefix;
101 } elseif ( $from != '' && $ns === null ) {
102 // For back-compat with Special:Allpages
103 // Don't do this if namespace is passed, so paging works when doing NS views.
104 $showme = $from;
105 }
106
107 // T29864: if transcluded, show all pages instead of the form.
108 if ( $this->including() || $showme != '' || $ns !== null ) {
109 $this->showPrefixChunk( $namespace, $showme, $from );
110 } else {
111 $out->addHTML( $this->namespacePrefixForm( $namespace, '' ) );
112 }
113 }
114
121 protected function namespacePrefixForm( $namespace = NS_MAIN, $from = '' ) {
122 $formDescriptor = [
123 'prefix' => [
124 'label-message' => 'allpagesprefix',
125 'name' => 'prefix',
126 'id' => 'nsfrom',
127 'type' => 'text',
128 'size' => '30',
129 'default' => str_replace( '_', ' ', $from ),
130 ],
131 'namespace' => [
132 'type' => 'namespaceselect',
133 'name' => 'namespace',
134 'id' => 'namespace',
135 'label-message' => 'namespace',
136 'all' => null,
137 'default' => $namespace,
138 ],
139 'hidedirects' => [
140 'class' => HTMLCheckField::class,
141 'name' => 'hideredirects',
142 'label-message' => 'allpages-hide-redirects',
143 ],
144 'stripprefix' => [
145 'class' => HTMLCheckField::class,
146 'name' => 'stripprefix',
147 'label-message' => 'prefixindex-strip',
148 ],
149 ];
150 $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() )
151 ->setMethod( 'get' )
152 ->setTitle( $this->getPageTitle() ) // Remove subpage
153 ->setWrapperLegendMsg( 'prefixindex' )
154 ->setSubmitTextMsg( 'prefixindex-submit' );
155
156 return $htmlForm->prepareForm()->getHTML( false );
157 }
158
164 protected function showPrefixChunk( $namespace, $prefix, $from = null ) {
165 if ( $from === null ) {
166 $from = $prefix;
167 }
168
169 $fromList = $this->getNamespaceKeyAndText( $namespace, $from );
170 $prefixList = $this->getNamespaceKeyAndText( $namespace, $prefix );
171 $namespaces = $this->getContentLanguage()->getNamespaces();
172 $res = null;
173 $n = 0;
174 $nextRow = null;
175
176 if ( !$prefixList || !$fromList ) {
177 $out = $this->msg( 'allpagesbadtitle' )->parseAsBlock();
178 } elseif ( !array_key_exists( $namespace, $namespaces ) ) {
179 // Show errormessage and reset to NS_MAIN
180 $out = $this->msg( 'allpages-bad-ns', $namespace )->parse();
181 $namespace = NS_MAIN;
182 } else {
183 [ $namespace, $prefixKey, $prefix ] = $prefixList;
184 [ /* $fromNS */, $fromKey, ] = $fromList;
185
186 # ## @todo FIXME: Should complain if $fromNs != $namespace
187
188 $dbr = $this->dbProvider->getReplicaDatabase();
189 $queryBuiler = $dbr->newSelectQueryBuilder()
190 ->select( LinkCache::getSelectFields() )
191 ->from( 'page' )
192 ->where( [
193 'page_namespace' => $namespace,
194 'page_title' . $dbr->buildLike( $prefixKey, $dbr->anyString() ),
195 'page_title >= ' . $dbr->addQuotes( $fromKey ),
196 ] )
197 ->orderBy( 'page_title' )
198 ->limit( $this->maxPerPage + 1 )
199 ->useIndex( 'page_name_title' );
200
201 if ( $this->hideRedirects ) {
202 $queryBuiler->andWhere( [ 'page_is_redirect' => 0 ] );
203 }
204
205 $res = $queryBuiler->caller( __METHOD__ )->fetchResultSet();
206
207 // @todo FIXME: Side link to previous
208
209 if ( $res->numRows() > 0 ) {
210 $out = Html::openElement( 'ul', [ 'class' => 'mw-prefixindex-list' ] );
211
212 $prefixLength = strlen( $prefix );
213 foreach ( $res as $row ) {
214 if ( $n >= $this->maxPerPage ) {
215 $nextRow = $row;
216 break;
217 }
218 $title = Title::newFromRow( $row );
219 // Make sure it gets into LinkCache
220 $this->linkCache->addGoodLinkObjFromRow( $title, $row );
221 $displayed = $title->getText();
222 // Try not to generate unclickable links
223 if ( $this->stripPrefix && $prefixLength !== strlen( $displayed ) ) {
224 $displayed = substr( $displayed, $prefixLength );
225 }
226 $link = ( $title->isRedirect() ? '<div class="allpagesredirect">' : '' ) .
227 $this->getLinkRenderer()->makeKnownLink(
228 $title,
229 $displayed
230 ) .
231 ( $title->isRedirect() ? '</div>' : '' );
232
233 $out .= "<li>$link</li>\n";
234 $n++;
235
236 }
237 $out .= Html::closeElement( 'ul' );
238
239 if ( $res->numRows() > 2 ) {
240 // Only apply CSS column styles if there's more than 2 entries.
241 // Otherwise rendering is broken as "mw-prefixindex-body"'s CSS column count is 3.
242 $out = Html::rawElement( 'div', [ 'class' => 'mw-prefixindex-body' ], $out );
243 }
244 } else {
245 $out = '';
246 }
247 }
248
249 $output = $this->getOutput();
250
251 if ( $this->including() ) {
252 // We don't show the nav-links and the form when included into other
253 // pages so let's just finish here.
254 $output->addHTML( $out );
255 return;
256 }
257
258 $topOut = $this->namespacePrefixForm( $namespace, $prefix );
259
260 if ( $res && ( $n == $this->maxPerPage ) && $nextRow ) {
261 $query = [
262 'from' => $nextRow->page_title,
263 'prefix' => $prefix,
264 'hideredirects' => $this->hideRedirects,
265 'stripprefix' => $this->stripPrefix,
266 ];
267
268 if ( $namespace || $prefix == '' ) {
269 // Keep the namespace even if it's 0 for empty prefixes.
270 // This tells us we're not just a holdover from old links.
271 $query['namespace'] = $namespace;
272 }
273
274 $nextLink = $this->getLinkRenderer()->makeKnownLink(
275 $this->getPageTitle(),
276 $this->msg( 'nextpage', str_replace( '_', ' ', $nextRow->page_title ) )->text(),
277 [],
278 $query
279 );
280
281 // Link shown at the top of the page below the form
282 $topOut .= Html::rawElement( 'div',
283 [ 'class' => 'mw-prefixindex-nav' ],
284 $nextLink
285 );
286
287 // Link shown at the footer
288 $out .= "\n" . Html::element( 'hr' ) .
289 Html::rawElement(
290 'div',
291 [ 'class' => 'mw-prefixindex-nav' ],
292 $nextLink
293 );
294
295 }
296
297 $output->addHTML( $topOut . $out );
298 }
299
300 protected function getGroupName() {
301 return 'pages';
302 }
303}
304
309class_alias( SpecialPrefixIndex::class, 'SpecialPrefixindex' );
const NS_MAIN
Definition Defines.php:64
A checkbox field.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:158
Cache for article titles (prefixed DB keys) and ids linked from one source.
Definition LinkCache.php:45
This class is a collection of static functions that serve two purposes:
Definition Html.php:57
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getPageTitle( $subpage=false)
Get a self-referential title object.
getContext()
Gets the context this SpecialPage is executed in.
getRequest()
Get the WebRequest being used for this instance.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getOutput()
Get the OutputPage being used for this instance.
getContentLanguage()
Shortcut to get content language.
including( $x=null)
Whether the special page is being evaluated via transclusion.
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
Implements Special:Allpages.
Implements Special:Prefixindex.
namespacePrefixForm( $namespace=NS_MAIN, $from='')
HTML for the top form.
__construct(IConnectionProvider $dbProvider, LinkCache $linkCache)
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
showPrefixChunk( $namespace, $prefix, $from=null)
execute( $par)
Entry point : initialise variables and call subfunctions.
$stripPrefix
Whether to remove the searched prefix from the displayed link.
Represents a title within MediaWiki.
Definition Title.php:76
Provide primary and replica IDatabase connections.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...