MediaWiki  master
SpecialPrefixindex.php
Go to the documentation of this file.
1 <?php
24 
31 
36  protected $stripPrefix = false;
37 
38  protected $hideRedirects = false;
39 
40  // Inherit $maxPerPage
41 
42  function __construct() {
43  parent::__construct( 'Prefixindex' );
44  }
45 
50  function execute( $par ) {
51  $this->setHeaders();
52  $this->outputHeader();
53 
54  $out = $this->getOutput();
55  $out->addModuleStyles( 'mediawiki.special' );
56 
57  # GET values
58  $request = $this->getRequest();
59  $from = $request->getVal( 'from', '' );
60  $prefix = $request->getVal( 'prefix', '' );
61  $ns = $request->getIntOrNull( 'namespace' );
62  $namespace = (int)$ns; // if no namespace given, use 0 (NS_MAIN).
63  $this->hideRedirects = $request->getBool( 'hideredirects', $this->hideRedirects );
64  $this->stripPrefix = $request->getBool( 'stripprefix', $this->stripPrefix );
65 
66  $namespaces = MediaWikiServices::getInstance()->getContentLanguage()->getNamespaces();
67  $out->setPageTitle(
68  ( $namespace > 0 && array_key_exists( $namespace, $namespaces ) )
69  ? $this->msg( 'prefixindex-namespace', str_replace( '_', ' ', $namespaces[$namespace] ) )
70  : $this->msg( 'prefixindex' )
71  );
72 
73  $showme = '';
74  if ( $par !== null ) {
75  $showme = $par;
76  } elseif ( $prefix != '' ) {
77  $showme = $prefix;
78  } elseif ( $from != '' && $ns === null ) {
79  // For back-compat with Special:Allpages
80  // Don't do this if namespace is passed, so paging works when doing NS views.
81  $showme = $from;
82  }
83 
84  // T29864: if transcluded, show all pages instead of the form.
85  if ( $this->including() || $showme != '' || $ns !== null ) {
86  $this->showPrefixChunk( $namespace, $showme, $from );
87  } else {
88  $out->addHTML( $this->namespacePrefixForm( $namespace, null ) );
89  }
90  }
91 
98  protected function namespacePrefixForm( $namespace = NS_MAIN, $from = '' ) {
99  $formDescriptor = [
100  'prefix' => [
101  'label-message' => 'allpagesprefix',
102  'name' => 'prefix',
103  'id' => 'nsfrom',
104  'type' => 'text',
105  'size' => '30',
106  'default' => str_replace( '_', ' ', $from ),
107  ],
108  'namespace' => [
109  'type' => 'namespaceselect',
110  'name' => 'namespace',
111  'id' => 'namespace',
112  'label-message' => 'namespace',
113  'all' => null,
114  'default' => $namespace,
115  ],
116  'hidedirects' => [
117  'class' => 'HTMLCheckField',
118  'name' => 'hideredirects',
119  'label-message' => 'allpages-hide-redirects',
120  ],
121  'stripprefix' => [
122  'class' => 'HTMLCheckField',
123  'name' => 'stripprefix',
124  'label-message' => 'prefixindex-strip',
125  ],
126  ];
127  $context = new DerivativeContext( $this->getContext() );
128  $context->setTitle( $this->getPageTitle() ); // Remove subpage
129  $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $context );
130  $htmlForm
131  ->setMethod( 'get' )
132  ->setWrapperLegendMsg( 'prefixindex' )
133  ->setSubmitTextMsg( 'prefixindex-submit' );
134 
135  return $htmlForm->prepareForm()->getHTML( false );
136  }
137 
143  protected function showPrefixChunk( $namespace, $prefix, $from = null ) {
144  if ( $from === null ) {
145  $from = $prefix;
146  }
147 
148  $fromList = $this->getNamespaceKeyAndText( $namespace, $from );
149  $prefixList = $this->getNamespaceKeyAndText( $namespace, $prefix );
150  $namespaces = MediaWikiServices::getInstance()->getContentLanguage()->getNamespaces();
151  $res = null;
152  $n = 0;
153  $nextRow = null;
154 
155  if ( !$prefixList || !$fromList ) {
156  $out = $this->msg( 'allpagesbadtitle' )->parseAsBlock();
157  } elseif ( !array_key_exists( $namespace, $namespaces ) ) {
158  // Show errormessage and reset to NS_MAIN
159  $out = $this->msg( 'allpages-bad-ns', $namespace )->parse();
160  $namespace = NS_MAIN;
161  } else {
162  list( $namespace, $prefixKey, $prefix ) = $prefixList;
163  list( /* $fromNS */, $fromKey, ) = $fromList;
164 
165  # ## @todo FIXME: Should complain if $fromNs != $namespace
166 
167  $dbr = wfGetDB( DB_REPLICA );
168 
169  $conds = [
170  'page_namespace' => $namespace,
171  'page_title' . $dbr->buildLike( $prefixKey, $dbr->anyString() ),
172  'page_title >= ' . $dbr->addQuotes( $fromKey ),
173  ];
174 
175  if ( $this->hideRedirects ) {
176  $conds['page_is_redirect'] = 0;
177  }
178 
179  $res = $dbr->select( 'page',
180  array_merge(
181  [ 'page_namespace', 'page_title' ],
183  ),
184  $conds,
185  __METHOD__,
186  [
187  'ORDER BY' => 'page_title',
188  'LIMIT' => $this->maxPerPage + 1,
189  'USE INDEX' => 'name_title',
190  ]
191  );
192 
193  // @todo FIXME: Side link to previous
194 
195  if ( $res->numRows() > 0 ) {
196  $out = Html::openElement( 'ul', [ 'class' => 'mw-prefixindex-list' ] );
197  $linkCache = MediaWikiServices::getInstance()->getLinkCache();
198 
199  $prefixLength = strlen( $prefix );
200  foreach ( $res as $row ) {
201  if ( $n >= $this->maxPerPage ) {
202  $nextRow = $row;
203  break;
204  }
205  $title = Title::newFromRow( $row );
206  // Make sure it gets into LinkCache
207  $linkCache->addGoodLinkObjFromRow( $title, $row );
208  $displayed = $title->getText();
209  // Try not to generate unclickable links
210  if ( $this->stripPrefix && $prefixLength !== strlen( $displayed ) ) {
211  $displayed = substr( $displayed, $prefixLength );
212  }
213  $link = ( $title->isRedirect() ? '<div class="allpagesredirect">' : '' ) .
214  $this->getLinkRenderer()->makeKnownLink(
215  $title,
216  $displayed
217  ) .
218  ( $title->isRedirect() ? '</div>' : '' );
219 
220  $out .= "<li>$link</li>\n";
221  $n++;
222 
223  }
224  $out .= Html::closeElement( 'ul' );
225 
226  if ( $res->numRows() > 2 ) {
227  // Only apply CSS column styles if there's more than 2 entries.
228  // Otherwise rendering is broken as "mw-prefixindex-body"'s CSS column count is 3.
229  $out = Html::rawElement( 'div', [ 'class' => 'mw-prefixindex-body' ], $out );
230  }
231  } else {
232  $out = '';
233  }
234  }
235 
236  $output = $this->getOutput();
237 
238  if ( $this->including() ) {
239  // We don't show the nav-links and the form when included into other
240  // pages so let's just finish here.
241  $output->addHTML( $out );
242  return;
243  }
244 
245  $topOut = $this->namespacePrefixForm( $namespace, $prefix );
246 
247  if ( $res && ( $n == $this->maxPerPage ) && $nextRow ) {
248  $query = [
249  'from' => $nextRow->page_title,
250  'prefix' => $prefix,
251  'hideredirects' => $this->hideRedirects,
252  'stripprefix' => $this->stripPrefix,
253  ];
254 
255  if ( $namespace || $prefix == '' ) {
256  // Keep the namespace even if it's 0 for empty prefixes.
257  // This tells us we're not just a holdover from old links.
258  $query['namespace'] = $namespace;
259  }
260 
261  $nextLink = $this->getLinkRenderer()->makeKnownLink(
262  $this->getPageTitle(),
263  $this->msg( 'nextpage', str_replace( '_', ' ', $nextRow->page_title ) )->text(),
264  [],
265  $query
266  );
267 
268  // Link shown at the top of the page below the form
269  $topOut .= Html::rawElement( 'div',
270  [ 'class' => 'mw-prefixindex-nav' ],
271  $nextLink
272  );
273 
274  // Link shown at the footer
275  $out .= "\n" . Html::element( 'hr' ) .
277  'div',
278  [ 'class' => 'mw-prefixindex-nav' ],
279  $nextLink
280  );
281 
282  }
283 
284  $output->addHTML( $topOut . $out );
285  }
286 
295  public function prefixSearchSubpages( $search, $limit, $offset ) {
296  return $this->prefixSearchString( $search, $limit, $offset );
297  }
298 
299  protected function getGroupName() {
300  return 'pages';
301  }
302 }
$stripPrefix
Whether to remove the searched prefix from the displayed link.
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:231
$context
Definition: load.php:45
getContext()
Gets the context this SpecialPage is executed in.
const NS_MAIN
Definition: Defines.php:60
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
including( $x=null)
Whether the special page is being evaluated via transclusion.
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing &#39;/&#39;...
Definition: Html.php:251
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:209
An IContextSource implementation which will inherit context from another source but allow individual ...
Implements Special:Allpages.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
namespacePrefixForm( $namespace=NS_MAIN, $from='')
HTML for the top form.
showPrefixChunk( $namespace, $prefix, $from=null)
getOutput()
Get the OutputPage being used for this instance.
static newFromRow( $row)
Make a Title object from a DB row.
Definition: Title.php:518
static factory( $displayFormat)
Construct a HTMLForm object for given display type.
Definition: HTMLForm.php:304
getNamespaceKeyAndText( $ns, $text)
prefixSearchString( $search, $limit, $offset)
Perform a regular substring search for prefixSearchSubpages.
execute( $par)
Entry point : initialise variables and call subfunctions.
static closeElement( $element)
Returns "</$element>".
Definition: Html.php:315
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes! ...
Implements Special:Prefixindex.
static getSelectFields()
Fields that LinkCache needs to select.
Definition: LinkCache.php:219
msg( $key)
Wrapper around wfMessage that sets the current context.
const DB_REPLICA
Definition: defines.php:25
getRequest()
Get the WebRequest being used for this instance.
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
getPageTitle( $subpage=false)
Get a self-referential title object.