MediaWiki  1.23.8
SpecialSearch.php
Go to the documentation of this file.
1 <?php
30 class SpecialSearch extends SpecialPage {
39  protected $profile;
40 
42  protected $searchEngine;
43 
45  protected $searchEngineType;
46 
48  protected $extraParams = array();
49 
51  protected $mPrefix;
52 
56  protected $limit, $offset;
57 
61  protected $namespaces;
62 
66  protected $didYouMeanHtml, $fulltext;
67 
68  const NAMESPACES_CURRENT = 'sense';
69 
70  public function __construct() {
71  parent::__construct( 'Search' );
72  }
73 
79  public function execute( $par ) {
80  $this->setHeaders();
81  $this->outputHeader();
82  $out = $this->getOutput();
83  $out->allowClickjacking();
84  $out->addModuleStyles( array(
85  'mediawiki.special', 'mediawiki.special.search', 'mediawiki.ui', 'mediawiki.ui.button'
86  ) );
87 
88  // Strip underscores from title parameter; most of the time we'll want
89  // text form here. But don't strip underscores from actual text params!
90  $titleParam = str_replace( '_', ' ', $par );
91 
92  $request = $this->getRequest();
93 
94  // Fetch the search term
95  $search = str_replace( "\n", " ", $request->getText( 'search', $titleParam ) );
96 
97  $this->load();
98 
99  $this->searchEngineType = $request->getVal( 'srbackend' );
100 
101  if ( $request->getVal( 'fulltext' )
102  || !is_null( $request->getVal( 'offset' ) )
103  ) {
104  $this->showResults( $search );
105  } else {
106  $this->goResult( $search );
107  }
108  }
109 
115  public function load() {
116  $request = $this->getRequest();
117  list( $this->limit, $this->offset ) = $request->getLimitOffset( 20 );
118  $this->mPrefix = $request->getVal( 'prefix', '' );
119 
120  $user = $this->getUser();
121 
122  # Extract manually requested namespaces
123  $nslist = $this->powerSearch( $request );
124  if ( !count( $nslist ) ) {
125  # Fallback to user preference
126  $nslist = SearchEngine::userNamespaces( $user );
127  }
128 
129  $profile = null;
130  if ( !count( $nslist ) ) {
131  $profile = 'default';
132  }
133 
134  $profile = $request->getVal( 'profile', $profile );
135  $profiles = $this->getSearchProfiles();
136  if ( $profile === null ) {
137  // BC with old request format
138  $profile = 'advanced';
139  foreach ( $profiles as $key => $data ) {
140  if ( $nslist === $data['namespaces'] && $key !== 'advanced' ) {
141  $profile = $key;
142  }
143  }
144  $this->namespaces = $nslist;
145  } elseif ( $profile === 'advanced' ) {
146  $this->namespaces = $nslist;
147  } else {
148  if ( isset( $profiles[$profile]['namespaces'] ) ) {
149  $this->namespaces = $profiles[$profile]['namespaces'];
150  } else {
151  // Unknown profile requested
152  $profile = 'default';
153  $this->namespaces = $profiles['default']['namespaces'];
154  }
155  }
156 
157  $this->didYouMeanHtml = ''; # html of did you mean... link
158  $this->fulltext = $request->getVal( 'fulltext' );
159  $this->profile = $profile;
160  }
161 
167  public function goResult( $term ) {
168  $this->setupPage( $term );
169  # Try to go to page as entered.
171  # If the string cannot be used to create a title
172  if ( is_null( $title ) ) {
173  $this->showResults( $term );
174 
175  return;
176  }
177  # If there's an exact or very near match, jump right there.
179 
180  if ( !wfRunHooks( 'SpecialSearchGo', array( &$title, &$term ) ) ) {
181  # Hook requested termination
182  return;
183  }
184 
185  if ( !is_null( $title ) ) {
186  $this->getOutput()->redirect( $title->getFullURL() );
187 
188  return;
189  }
190  # No match, generate an edit URL
192  if ( !is_null( $title ) ) {
193  global $wgGoToEdit;
194  wfRunHooks( 'SpecialSearchNogomatch', array( &$title ) );
195  wfDebugLog( 'nogomatch', $title->getFullText(), 'private' );
196 
197  # If the feature is enabled, go straight to the edit page
198  if ( $wgGoToEdit ) {
199  $this->getOutput()->redirect( $title->getFullURL( array( 'action' => 'edit' ) ) );
200 
201  return;
202  }
203  }
204  $this->showResults( $term );
205  }
206 
210  public function showResults( $term ) {
211  global $wgDisableTextSearch, $wgSearchForwardUrl, $wgContLang, $wgScript;
212 
213  $profile = new ProfileSection( __METHOD__ );
214  $search = $this->getSearchEngine();
215  $search->setLimitOffset( $this->limit, $this->offset );
216  $search->setNamespaces( $this->namespaces );
217  $search->prefix = $this->mPrefix;
218  $term = $search->transformSearchTerm( $term );
219 
220  wfRunHooks( 'SpecialSearchSetupEngine', array( $this, $this->profile, $search ) );
221 
222  $this->setupPage( $term );
223 
224  $out = $this->getOutput();
225 
226  if ( $wgDisableTextSearch ) {
227  if ( $wgSearchForwardUrl ) {
228  $url = str_replace( '$1', urlencode( $term ), $wgSearchForwardUrl );
229  $out->redirect( $url );
230  } else {
231  $out->addHTML(
232  Xml::openElement( 'fieldset' ) .
233  Xml::element( 'legend', null, $this->msg( 'search-external' )->text() ) .
234  Xml::element( 'p', array( 'class' => 'mw-searchdisabled' ), $this->msg( 'searchdisabled' )->text() ) .
235  $this->msg( 'googlesearch' )->rawParams(
236  htmlspecialchars( $term ),
237  'UTF-8',
238  $this->msg( 'searchbutton' )->escaped()
239  )->text() .
240  Xml::closeElement( 'fieldset' )
241  );
242  }
243 
244  return;
245  }
246 
248  $showSuggestion = $title === null || !$title->isKnown();
249  $search->setShowSuggestion( $showSuggestion );
250 
251  // fetch search results
252  $rewritten = $search->replacePrefixes( $term );
253 
254  $titleMatches = $search->searchTitle( $rewritten );
255  if ( !( $titleMatches instanceof SearchResultTooMany ) ) {
256  $textMatches = $search->searchText( $rewritten );
257  }
258 
259  $textStatus = null;
260  if ( $textMatches instanceof Status ) {
261  $textStatus = $textMatches;
262  $textMatches = null;
263  }
264 
265  // did you mean... suggestions
266  if ( $showSuggestion && $textMatches && !$textStatus && $textMatches->hasSuggestion() ) {
267  $st = SpecialPage::getTitleFor( 'Search' );
268 
269  # mirror Go/Search behavior of original request ..
270  $didYouMeanParams = array( 'search' => $textMatches->getSuggestionQuery() );
271 
272  if ( $this->fulltext != null ) {
273  $didYouMeanParams['fulltext'] = $this->fulltext;
274  }
275 
276  $stParams = array_merge(
277  $didYouMeanParams,
278  $this->powerSearchOptions()
279  );
280 
281  $suggestionSnippet = $textMatches->getSuggestionSnippet();
282 
283  if ( $suggestionSnippet == '' ) {
284  $suggestionSnippet = null;
285  }
286 
287  $suggestLink = Linker::linkKnown(
288  $st,
289  $suggestionSnippet,
290  array(),
291  $stParams
292  );
293 
294  $this->didYouMeanHtml = '<div class="searchdidyoumean">' . $this->msg( 'search-suggest' )->rawParams( $suggestLink )->text() . '</div>';
295  }
296 
297  if ( !wfRunHooks( 'SpecialSearchResultsPrepend', array( $this, $out, $term ) ) ) {
298  # Hook requested termination
299  return;
300  }
301 
302  // start rendering the page
303  $out->addHtml(
305  'form',
306  array(
307  'id' => ( $this->profile === 'advanced' ? 'powersearch' : 'search' ),
308  'method' => 'get',
309  'action' => $wgScript
310  )
311  )
312  );
313  $out->addHtml(
314  # This is an awful awful ID name. It's not a table, but we
315  # named it poorly from when this was a table so now we're
316  # stuck with it
317  Xml::openElement( 'div', array( 'id' => 'mw-search-top-table' ) ) .
318  $this->shortDialog( $term ) .
319  Xml::closeElement( 'div' )
320  );
321 
322  // Sometimes the search engine knows there are too many hits
323  if ( $titleMatches instanceof SearchResultTooMany ) {
324  $out->wrapWikiMsg( "==$1==\n", 'toomanymatches' );
325 
326  return;
327  }
328 
329  $filePrefix = $wgContLang->getFormattedNsText( NS_FILE ) . ':';
330  if ( trim( $term ) === '' || $filePrefix === trim( $term ) ) {
331  $out->addHTML( $this->formHeader( $term, 0, 0 ) );
332  $out->addHtml( $this->getProfileForm( $this->profile, $term ) );
333  $out->addHTML( '</form>' );
334 
335  // Empty query -- straight view of search form
336  return;
337  }
338 
339  // Get number of results
340  $titleMatchesNum = $titleMatches ? $titleMatches->numRows() : 0;
341  $textMatchesNum = $textMatches ? $textMatches->numRows() : 0;
342  // Total initial query matches (possible false positives)
343  $num = $titleMatchesNum + $textMatchesNum;
344 
345  // Get total actual results (after second filtering, if any)
346  $numTitleMatches = $titleMatches && !is_null( $titleMatches->getTotalHits() ) ?
347  $titleMatches->getTotalHits() : $titleMatchesNum;
348  $numTextMatches = $textMatches && !is_null( $textMatches->getTotalHits() ) ?
349  $textMatches->getTotalHits() : $textMatchesNum;
350 
351  // get total number of results if backend can calculate it
352  $totalRes = 0;
353  if ( $titleMatches && !is_null( $titleMatches->getTotalHits() ) ) {
354  $totalRes += $titleMatches->getTotalHits();
355  }
356  if ( $textMatches && !is_null( $textMatches->getTotalHits() ) ) {
357  $totalRes += $textMatches->getTotalHits();
358  }
359 
360  // show number of results and current offset
361  $out->addHTML( $this->formHeader( $term, $num, $totalRes ) );
362  $out->addHtml( $this->getProfileForm( $this->profile, $term ) );
363 
364  $out->addHtml( Xml::closeElement( 'form' ) );
365  $out->addHtml( "<div class='searchresults'>" );
366 
367  // prev/next links
368  if ( $num || $this->offset ) {
369  // Show the create link ahead
370  $this->showCreateLink( $title, $num, $titleMatches, $textMatches );
371  $prevnext = $this->getLanguage()->viewPrevNext( $this->getPageTitle(), $this->offset, $this->limit,
372  $this->powerSearchOptions() + array( 'search' => $term ),
373  max( $titleMatchesNum, $textMatchesNum ) < $this->limit
374  );
375  //$out->addHTML( "<p class='mw-search-pager-top'>{$prevnext}</p>\n" );
376  wfRunHooks( 'SpecialSearchResults', array( $term, &$titleMatches, &$textMatches ) );
377  } else {
378  wfRunHooks( 'SpecialSearchNoResults', array( $term ) );
379  }
380 
381  $out->parserOptions()->setEditSection( false );
382  if ( $titleMatches ) {
383  if ( $numTitleMatches > 0 ) {
384  $out->wrapWikiMsg( "==$1==\n", 'titlematches' );
385  $out->addHTML( $this->showMatches( $titleMatches ) );
386  }
387  $titleMatches->free();
388  }
389  if ( $textMatches && !$textStatus ) {
390  // output appropriate heading
391  if ( $numTextMatches > 0 && $numTitleMatches > 0 ) {
392  // if no title matches the heading is redundant
393  $out->wrapWikiMsg( "==$1==\n", 'textmatches' );
394  } elseif ( $totalRes == 0 ) {
395  # Don't show the 'no text matches' if we received title matches
396  # $out->wrapWikiMsg( "==$1==\n", 'notextmatches' );
397  }
398  // show interwiki results if any
399  if ( $textMatches->hasInterwikiResults() ) {
400  $out->addHTML( $this->showInterwiki( $textMatches->getInterwikiResults(), $term ) );
401  }
402  // show results
403  if ( $numTextMatches > 0 ) {
404  $out->addHTML( $this->showMatches( $textMatches ) );
405  }
406 
407  $textMatches->free();
408  }
409  if ( $num === 0 ) {
410  if ( $textStatus ) {
411  $out->addHTML( '<div class="error">' .
412  htmlspecialchars( $textStatus->getWikiText( 'search-error' ) ) . '</div>' );
413  } else {
414  $out->wrapWikiMsg( "<p class=\"mw-search-nonefound\">\n$1</p>",
415  array( 'search-nonefound', wfEscapeWikiText( $term ) ) );
416  $this->showCreateLink( $title, $num, $titleMatches, $textMatches );
417  }
418  }
419  $out->addHtml( "</div>" );
420 
421  if ( $num || $this->offset ) {
422  $out->addHTML( "<p class='mw-search-pager-bottom'>{$prevnext}</p>\n" );
423  }
424  wfRunHooks( 'SpecialSearchResultsAppend', array( $this, $out, $term ) );
425  }
426 
433  protected function showCreateLink( $title, $num, $titleMatches, $textMatches ) {
434  // show direct page/create link if applicable
435 
436  // Check DBkey !== '' in case of fragment link only.
437  if ( is_null( $title ) || $title->getDBkey() === ''
438  || ( $titleMatches !== null && $titleMatches->searchContainedSyntax() )
439  || ( $textMatches !== null && $textMatches->searchContainedSyntax() )
440  ) {
441  // invalid title
442  // preserve the paragraph for margins etc...
443  $this->getOutput()->addHtml( '<p></p>' );
444 
445  return;
446  }
447 
448  if ( $title->isKnown() ) {
449  $messageName = 'searchmenu-exists';
450  } elseif ( $title->userCan( 'create', $this->getUser() ) ) {
451  $messageName = 'searchmenu-new';
452  } else {
453  $messageName = 'searchmenu-new-nocreate';
454  }
455  $params = array( $messageName, wfEscapeWikiText( $title->getPrefixedText() ), Message::numParam( $num ) );
456  wfRunHooks( 'SpecialSearchCreateLink', array( $title, &$params ) );
457 
458  // Extensions using the hook might still return an empty $messageName
459  if ( $messageName ) {
460  $this->getOutput()->wrapWikiMsg( "<p class=\"mw-search-createlink\">\n$1</p>", $params );
461  } else {
462  // preserve the paragraph for margins etc...
463  $this->getOutput()->addHtml( '<p></p>' );
464  }
465  }
466 
470  protected function setupPage( $term ) {
471  # Should advanced UI be used?
472  $this->searchAdvanced = ( $this->profile === 'advanced' );
473  $out = $this->getOutput();
474  if ( strval( $term ) !== '' ) {
475  $out->setPageTitle( $this->msg( 'searchresults' ) );
476  $out->setHTMLTitle( $this->msg( 'pagetitle' )
477  ->rawParams( $this->msg( 'searchresults-title' )->rawParams( $term )->text() )
478  ->inContentLanguage()->text()
479  );
480  }
481  // add javascript specific to special:search
482  $out->addModules( 'mediawiki.special.search' );
483  }
484 
492  protected function powerSearch( &$request ) {
493  $arr = array();
494  foreach ( SearchEngine::searchableNamespaces() as $ns => $name ) {
495  if ( $request->getCheck( 'ns' . $ns ) ) {
496  $arr[] = $ns;
497  }
498  }
499 
500  return $arr;
501  }
502 
508  protected function powerSearchOptions() {
509  $opt = array();
510  if ( $this->profile !== 'advanced' ) {
511  $opt['profile'] = $this->profile;
512  } else {
513  foreach ( $this->namespaces as $n ) {
514  $opt['ns' . $n] = 1;
515  }
516  }
517 
518  return $opt + $this->extraParams;
519  }
520 
528  protected function showMatches( &$matches ) {
530 
531  $profile = new ProfileSection( __METHOD__ );
532  $terms = $wgContLang->convertForSearchResult( $matches->termMatches() );
533 
534  $out = "<ul class='mw-search-results'>\n";
535  $result = $matches->next();
536  while ( $result ) {
537  $out .= $this->showHit( $result, $terms );
538  $result = $matches->next();
539  }
540  $out .= "</ul>\n";
541 
542  // convert the whole thing to desired language variant
543  $out = $wgContLang->convert( $out );
544 
545  return $out;
546  }
547 
556  protected function showHit( $result, $terms ) {
557  $profile = new ProfileSection( __METHOD__ );
558 
559  if ( $result->isBrokenTitle() ) {
560  return "<!-- Broken link in search result -->\n";
561  }
562 
563  $title = $result->getTitle();
564 
565  $titleSnippet = $result->getTitleSnippet( $terms );
566 
567  if ( $titleSnippet == '' ) {
568  $titleSnippet = null;
569  }
570 
571  $link_t = clone $title;
572 
573  wfRunHooks( 'ShowSearchHitTitle',
574  array( &$link_t, &$titleSnippet, $result, $terms, $this ) );
575 
577  $link_t,
578  $titleSnippet
579  );
580 
581  //If page content is not readable, just return the title.
582  //This is not quite safe, but better than showing excerpts from non-readable pages
583  //Note that hiding the entry entirely would screw up paging.
584  if ( !$title->userCan( 'read', $this->getUser() ) ) {
585  return "<li>{$link}</li>\n";
586  }
587 
588  // If the page doesn't *exist*... our search index is out of date.
589  // The least confusing at this point is to drop the result.
590  // You may get less results, but... oh well. :P
591  if ( $result->isMissingRevision() ) {
592  return "<!-- missing page " . htmlspecialchars( $title->getPrefixedText() ) . "-->\n";
593  }
594 
595  // format redirects / relevant sections
596  $redirectTitle = $result->getRedirectTitle();
597  $redirectText = $result->getRedirectSnippet( $terms );
598  $sectionTitle = $result->getSectionTitle();
599  $sectionText = $result->getSectionSnippet( $terms );
600  $redirect = '';
601 
602  if ( !is_null( $redirectTitle ) ) {
603  if ( $redirectText == '' ) {
604  $redirectText = null;
605  }
606 
607  $redirect = "<span class='searchalttitle'>" .
608  $this->msg( 'search-redirect' )->rawParams(
609  Linker::linkKnown( $redirectTitle, $redirectText ) )->text() .
610  "</span>";
611  }
612 
613  $section = '';
614 
615  if ( !is_null( $sectionTitle ) ) {
616  if ( $sectionText == '' ) {
617  $sectionText = null;
618  }
619 
620  $section = "<span class='searchalttitle'>" .
621  $this->msg( 'search-section' )->rawParams(
622  Linker::linkKnown( $sectionTitle, $sectionText ) )->text() .
623  "</span>";
624  }
625 
626  // format text extract
627  $extract = "<div class='searchresult'>" . $result->getTextSnippet( $terms ) . "</div>";
628 
629  $lang = $this->getLanguage();
630 
631  // format score
632  if ( is_null( $result->getScore() ) ) {
633  // Search engine doesn't report scoring info
634  $score = '';
635  } else {
636  $percent = sprintf( '%2.1f', $result->getScore() * 100 );
637  $score = $this->msg( 'search-result-score' )->numParams( $percent )->text()
638  . ' - ';
639  }
640 
641  // format description
642  $byteSize = $result->getByteSize();
643  $wordCount = $result->getWordCount();
644  $timestamp = $result->getTimestamp();
645  $size = $this->msg( 'search-result-size', $lang->formatSize( $byteSize ) )
646  ->numParams( $wordCount )->escaped();
647 
648  if ( $title->getNamespace() == NS_CATEGORY ) {
649  $cat = Category::newFromTitle( $title );
650  $size = $this->msg( 'search-result-category-size' )
651  ->numParams( $cat->getPageCount(), $cat->getSubcatCount(), $cat->getFileCount() )
652  ->escaped();
653  }
654 
655  $date = $lang->userTimeAndDate( $timestamp, $this->getUser() );
656 
657  // link to related articles if supported
658  $related = '';
659  if ( $result->hasRelated() ) {
660  $st = SpecialPage::getTitleFor( 'Search' );
661  $stParams = array_merge(
662  $this->powerSearchOptions(),
663  array(
664  'search' => $this->msg( 'searchrelated' )->inContentLanguage()->text() .
665  ':' . $title->getPrefixedText(),
666  'fulltext' => $this->msg( 'search' )->text()
667  )
668  );
669 
670  $related = ' -- ' . Linker::linkKnown(
671  $st,
672  $this->msg( 'search-relatedarticle' )->text(),
673  array(),
674  $stParams
675  );
676  }
677 
678  $fileMatch = '';
679  // Include a thumbnail for media files...
680  if ( $title->getNamespace() == NS_FILE ) {
681  $img = $result->getFile();
682  $img = $img ?: wfFindFile( $title );
683  if ( $result->isFileMatch() ) {
684  $fileMatch = "<span class='searchalttitle'>" .
685  $this->msg( 'search-file-match' )->escaped() . "</span>";
686  }
687  if ( $img ) {
688  $thumb = $img->transform( array( 'width' => 120, 'height' => 120 ) );
689  if ( $thumb ) {
690  $desc = $this->msg( 'parentheses' )->rawParams( $img->getShortDesc() )->escaped();
691  // Float doesn't seem to interact well with the bullets.
692  // Table messes up vertical alignment of the bullets.
693  // Bullets are therefore disabled (didn't look great anyway).
694  return "<li>" .
695  '<table class="searchResultImage">' .
696  '<tr>' .
697  '<td style="width: 120px; text-align: center; vertical-align: top;">' .
698  $thumb->toHtml( array( 'desc-link' => true ) ) .
699  '</td>' .
700  '<td style="vertical-align: top;">' .
701  "{$link} {$fileMatch}" .
702  $extract .
703  "<div class='mw-search-result-data'>{$score}{$desc} - {$date}{$related}</div>" .
704  '</td>' .
705  '</tr>' .
706  '</table>' .
707  "</li>\n";
708  }
709  }
710  }
711 
712  $html = null;
713 
714  if ( wfRunHooks( 'ShowSearchHit', array(
715  $this, $result, $terms,
716  &$link, &$redirect, &$section, &$extract,
717  &$score, &$size, &$date, &$related,
718  &$html
719  ) ) ) {
720  $html = "<li><div class='mw-search-result-heading'>{$link} {$redirect} {$section} {$fileMatch}</div> {$extract}\n" .
721  "<div class='mw-search-result-data'>{$score}{$size} - {$date}{$related}</div>" .
722  "</li>\n";
723  }
724 
725  return $html;
726  }
727 
736  protected function showInterwiki( $matches, $query ) {
738  $profile = new ProfileSection( __METHOD__ );
739 
740  $out = "<div id='mw-search-interwiki'><div id='mw-search-interwiki-caption'>" .
741  $this->msg( 'search-interwiki-caption' )->text() . "</div>\n";
742  $out .= "<ul class='mw-search-iwresults'>\n";
743 
744  // work out custom project captions
745  $customCaptions = array();
746  $customLines = explode( "\n", $this->msg( 'search-interwiki-custom' )->text() ); // format per line <iwprefix>:<caption>
747  foreach ( $customLines as $line ) {
748  $parts = explode( ":", $line, 2 );
749  if ( count( $parts ) == 2 ) { // validate line
750  $customCaptions[$parts[0]] = $parts[1];
751  }
752  }
753 
754  if ( !is_array( $matches ) ) {
755  $matches = array( $matches );
756  }
757 
758  foreach ( $matches as $set ) {
759  $prev = null;
760  $result = $set->next();
761  while ( $result ) {
762  $out .= $this->showInterwikiHit( $result, $prev, $query, $customCaptions );
763  $prev = $result->getInterwikiPrefix();
764  $result = $set->next();
765  }
766  }
767 
768 
769  // TODO: should support paging in a non-confusing way (not sure how though, maybe via ajax)..
770  $out .= "</ul></div>\n";
771 
772  // convert the whole thing to desired language variant
773  $out = $wgContLang->convert( $out );
774 
775  return $out;
776  }
777 
788  protected function showInterwikiHit( $result, $lastInterwiki, $query, $customCaptions ) {
789  $profile = new ProfileSection( __METHOD__ );
790 
791  if ( $result->isBrokenTitle() ) {
792  return "<!-- Broken link in search result -->\n";
793  }
794 
795  $title = $result->getTitle();
796 
797  $titleSnippet = $result->getTitleSnippet();
798 
799  if ( $titleSnippet == '' ) {
800  $titleSnippet = null;
801  }
802 
804  $title,
805  $titleSnippet
806  );
807 
808  // format redirect if any
809  $redirectTitle = $result->getRedirectTitle();
810  $redirectText = $result->getRedirectSnippet();
811  $redirect = '';
812  if ( !is_null( $redirectTitle ) ) {
813  if ( $redirectText == '' ) {
814  $redirectText = null;
815  }
816 
817  $redirect = "<span class='searchalttitle'>" .
818  $this->msg( 'search-redirect' )->rawParams(
819  Linker::linkKnown( $redirectTitle, $redirectText ) )->text() .
820  "</span>";
821  }
822 
823  $out = "";
824  // display project name
825  if ( is_null( $lastInterwiki ) || $lastInterwiki != $title->getInterwiki() ) {
826  if ( array_key_exists( $title->getInterwiki(), $customCaptions ) ) {
827  // captions from 'search-interwiki-custom'
828  $caption = $customCaptions[$title->getInterwiki()];
829  } else {
830  // default is to show the hostname of the other wiki which might suck
831  // if there are many wikis on one hostname
832  $parsed = wfParseUrl( $title->getFullURL() );
833  $caption = $this->msg( 'search-interwiki-default', $parsed['host'] )->text();
834  }
835  // "more results" link (special page stuff could be localized, but we might not know target lang)
836  $searchTitle = Title::newFromText( $title->getInterwiki() . ":Special:Search" );
837  $searchLink = Linker::linkKnown(
838  $searchTitle,
839  $this->msg( 'search-interwiki-more' )->text(),
840  array(),
841  array(
842  'search' => $query,
843  'fulltext' => 'Search'
844  )
845  );
846  $out .= "</ul><div class='mw-search-interwiki-project'><span class='mw-search-interwiki-more'>
847  {$searchLink}</span>{$caption}</div>\n<ul>";
848  }
849 
850  $out .= "<li>{$link} {$redirect}</li>\n";
851 
852  return $out;
853  }
854 
860  protected function getProfileForm( $profile, $term ) {
861  // Hidden stuff
862  $opts = array();
863  $opts['profile'] = $this->profile;
864 
865  if ( $profile === 'advanced' ) {
866  return $this->powerSearchBox( $term, $opts );
867  } else {
868  $form = '';
869  wfRunHooks( 'SpecialSearchProfileForm', array( $this, &$form, $profile, $term, $opts ) );
870 
871  return $form;
872  }
873  }
874 
882  protected function powerSearchBox( $term, $opts ) {
884 
885  // Groups namespaces into rows according to subject
886  $rows = array();
887  foreach ( SearchEngine::searchableNamespaces() as $namespace => $name ) {
888  $subject = MWNamespace::getSubject( $namespace );
889  if ( !array_key_exists( $subject, $rows ) ) {
890  $rows[$subject] = "";
891  }
892 
893  $name = $wgContLang->getConverter()->convertNamespace( $namespace );
894  if ( $name == '' ) {
895  $name = $this->msg( 'blanknamespace' )->text();
896  }
897 
898  $rows[$subject] .=
900  'td', array( 'style' => 'white-space: nowrap' )
901  ) .
903  $name,
904  "ns{$namespace}",
905  "mw-search-ns{$namespace}",
906  in_array( $namespace, $this->namespaces )
907  ) .
908  Xml::closeElement( 'td' );
909  }
910 
911  $rows = array_values( $rows );
912  $numRows = count( $rows );
913 
914  // Lays out namespaces in multiple floating two-column tables so they'll
915  // be arranged nicely while still accommodating different screen widths
916  $namespaceTables = '';
917  for ( $i = 0; $i < $numRows; $i += 4 ) {
918  $namespaceTables .= Xml::openElement(
919  'table',
920  array( 'cellpadding' => 0, 'cellspacing' => 0 )
921  );
922 
923  for ( $j = $i; $j < $i + 4 && $j < $numRows; $j++ ) {
924  $namespaceTables .= Xml::tags( 'tr', null, $rows[$j] );
925  }
926 
927  $namespaceTables .= Xml::closeElement( 'table' );
928  }
929 
930  $showSections = array( 'namespaceTables' => $namespaceTables );
931 
932  wfRunHooks( 'SpecialSearchPowerBox', array( &$showSections, $term, $opts ) );
933 
934  $hidden = '';
935  foreach ( $opts as $key => $value ) {
936  $hidden .= Html::hidden( $key, $value );
937  }
938 
939  // Return final output
940  return Xml::openElement(
941  'fieldset',
942  array( 'id' => 'mw-searchoptions', 'style' => 'margin:0em;' )
943  ) .
944  Xml::element( 'legend', null, $this->msg( 'powersearch-legend' )->text() ) .
945  Xml::tags( 'h4', null, $this->msg( 'powersearch-ns' )->parse() ) .
946  Html::element( 'div', array( 'id' => 'mw-search-togglebox' ) ) .
947  Xml::element( 'div', array( 'class' => 'divider' ), '', false ) .
948  implode( Xml::element( 'div', array( 'class' => 'divider' ), '', false ), $showSections ) .
949  $hidden .
950  Xml::closeElement( 'fieldset' );
951  }
952 
956  protected function getSearchProfiles() {
957  // Builds list of Search Types (profiles)
958  $nsAllSet = array_keys( SearchEngine::searchableNamespaces() );
959 
960  $profiles = array(
961  'default' => array(
962  'message' => 'searchprofile-articles',
963  'tooltip' => 'searchprofile-articles-tooltip',
964  'namespaces' => SearchEngine::defaultNamespaces(),
965  'namespace-messages' => SearchEngine::namespacesAsText(
967  ),
968  ),
969  'images' => array(
970  'message' => 'searchprofile-images',
971  'tooltip' => 'searchprofile-images-tooltip',
972  'namespaces' => array( NS_FILE ),
973  ),
974  'help' => array(
975  'message' => 'searchprofile-project',
976  'tooltip' => 'searchprofile-project-tooltip',
977  'namespaces' => SearchEngine::helpNamespaces(),
978  'namespace-messages' => SearchEngine::namespacesAsText(
980  ),
981  ),
982  'all' => array(
983  'message' => 'searchprofile-everything',
984  'tooltip' => 'searchprofile-everything-tooltip',
985  'namespaces' => $nsAllSet,
986  ),
987  'advanced' => array(
988  'message' => 'searchprofile-advanced',
989  'tooltip' => 'searchprofile-advanced-tooltip',
990  'namespaces' => self::NAMESPACES_CURRENT,
991  )
992  );
993 
994  wfRunHooks( 'SpecialSearchProfiles', array( &$profiles ) );
995 
996  foreach ( $profiles as &$data ) {
997  if ( !is_array( $data['namespaces'] ) ) {
998  continue;
999  }
1000  sort( $data['namespaces'] );
1001  }
1002 
1003  return $profiles;
1004  }
1005 
1012  protected function formHeader( $term, $resultsShown, $totalNum ) {
1013  $out = Xml::openElement( 'div', array( 'class' => 'mw-search-formheader' ) );
1014 
1015  $bareterm = $term;
1016  if ( $this->startsWithImage( $term ) ) {
1017  // Deletes prefixes
1018  $bareterm = substr( $term, strpos( $term, ':' ) + 1 );
1019  }
1020 
1021  $profiles = $this->getSearchProfiles();
1022  $lang = $this->getLanguage();
1023 
1024  // Outputs XML for Search Types
1025  $out .= Xml::openElement( 'div', array( 'class' => 'search-types' ) );
1026  $out .= Xml::openElement( 'ul' );
1027  foreach ( $profiles as $id => $profile ) {
1028  if ( !isset( $profile['parameters'] ) ) {
1029  $profile['parameters'] = array();
1030  }
1031  $profile['parameters']['profile'] = $id;
1032 
1033  $tooltipParam = isset( $profile['namespace-messages'] ) ?
1034  $lang->commaList( $profile['namespace-messages'] ) : null;
1035  $out .= Xml::tags(
1036  'li',
1037  array(
1038  'class' => $this->profile === $id ? 'current' : 'normal'
1039  ),
1040  $this->makeSearchLink(
1041  $bareterm,
1042  array(),
1043  $this->msg( $profile['message'] )->text(),
1044  $this->msg( $profile['tooltip'], $tooltipParam )->text(),
1045  $profile['parameters']
1046  )
1047  );
1048  }
1049  $out .= Xml::closeElement( 'ul' );
1050  $out .= Xml::closeElement( 'div' );
1051 
1052  // Results-info
1053  if ( $resultsShown > 0 ) {
1054  if ( $totalNum > 0 ) {
1055  $top = $this->msg( 'showingresultsheader' )
1056  ->numParams( $this->offset + 1, $this->offset + $resultsShown, $totalNum )
1057  ->params( wfEscapeWikiText( $term ) )
1058  ->numParams( $resultsShown )
1059  ->parse();
1060  } elseif ( $resultsShown >= $this->limit ) {
1061  $top = $this->msg( 'showingresults' )
1062  ->numParams( $this->limit, $this->offset + 1 )
1063  ->parse();
1064  } else {
1065  $top = $this->msg( 'showingresultsnum' )
1066  ->numParams( $this->limit, $this->offset + 1, $resultsShown )
1067  ->parse();
1068  }
1069  $out .= Xml::tags( 'div', array( 'class' => 'results-info' ),
1070  Xml::tags( 'ul', null, Xml::tags( 'li', null, $top ) )
1071  );
1072  }
1073 
1074  $out .= Xml::element( 'div', array( 'style' => 'clear:both' ), '', false );
1075  $out .= Xml::closeElement( 'div' );
1077  return $out;
1078  }
1079 
1084  protected function shortDialog( $term ) {
1085  $out = Html::hidden( 'title', $this->getPageTitle()->getPrefixedText() );
1086  $out .= Html::hidden( 'profile', $this->profile ) . "\n";
1087  // Term box
1088  $out .= Html::input( 'search', $term, 'search', array(
1089  'id' => $this->profile === 'advanced' ? 'powerSearchText' : 'searchText',
1090  'size' => '50',
1091  'autofocus',
1092  'class' => 'mw-ui-input',
1093  ) ) . "\n";
1094  $out .= Html::hidden( 'fulltext', 'Search' ) . "\n";
1096  $this->msg( 'searchbutton' )->text(),
1097  array( 'class' => array( 'mw-ui-button', 'mw-ui-progressive' ) )
1098  ) . "\n";
1099 
1100  return $out . $this->didYouMeanHtml;
1101  }
1102 
1113  protected function makeSearchLink( $term, $namespaces, $label, $tooltip, $params = array() ) {
1114  $opt = $params;
1115  foreach ( $namespaces as $n ) {
1116  $opt['ns' . $n] = 1;
1117  }
1118 
1119  $stParams = array_merge(
1120  array(
1121  'search' => $term,
1122  'fulltext' => $this->msg( 'search' )->text()
1123  ),
1124  $opt
1125  );
1126 
1127  return Xml::element(
1128  'a',
1129  array(
1130  'href' => $this->getPageTitle()->getLocalURL( $stParams ),
1131  'title' => $tooltip
1132  ),
1133  $label
1134  );
1135  }
1136 
1143  protected function startsWithImage( $term ) {
1145 
1146  $parts = explode( ':', $term );
1147  if ( count( $parts ) > 1 ) {
1148  return $wgContLang->getNsIndex( $parts[0] ) == NS_FILE;
1149  }
1150 
1151  return false;
1152  }
1153 
1160  protected function startsWithAll( $term ) {
1161 
1162  $allkeyword = $this->msg( 'searchall' )->inContentLanguage()->text();
1163 
1164  $parts = explode( ':', $term );
1165  if ( count( $parts ) > 1 ) {
1166  return $parts[0] == $allkeyword;
1167  }
1168 
1169  return false;
1170  }
1171 
1177  public function getSearchEngine() {
1178  if ( $this->searchEngine === null ) {
1179  $this->searchEngine = $this->searchEngineType ?
1180  SearchEngine::create( $this->searchEngineType ) : SearchEngine::create();
1181  }
1183  return $this->searchEngine;
1184  }
1185 
1190  function getProfile() {
1191  return $this->profile;
1192  }
1193 
1198  function getNamespaces() {
1199  return $this->namespaces;
1200  }
1201 
1211  public function setExtraParam( $key, $value ) {
1212  $this->extraParams[$key] = $value;
1213  }
1214 
1215  protected function getGroupName() {
1216  return 'pages';
1217  }
1218 }
Xml\checkLabel
static checkLabel( $label, $name, $id, $checked=false, $attribs=array())
Convenience function to build an HTML checkbox with a label.
Definition: Xml.php:433
SpecialSearch\getNamespaces
getNamespaces()
Current namespaces.
Definition: SpecialSearch.php:1190
SpecialPage\getPageTitle
getPageTitle( $subpage=false)
Get a self-referential title object.
Definition: SpecialPage.php:488
$result
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. $reader:XMLReader object $logInfo:Array of information Return false to stop further processing of the tag 'ImportHandlePageXMLTag':When parsing a XML tag in a page. $reader:XMLReader object $pageInfo:Array of information Return false to stop further processing of the tag 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information Return false to stop further processing of the tag 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. $reader:XMLReader object Return false to stop further processing of the tag 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. $reader:XMLReader object $revisionInfo:Array of information Return false to stop further processing of the tag 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. $title:Title object for the current page $request:WebRequest $ignoreRedirect:boolean to skip redirect check $target:Title/string of redirect target $article:Article object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) $article:article(object) being checked 'IsTrustedProxy':Override the result of wfIsTrustedProxy() $ip:IP being check $result:Change this value to override the result of wfIsTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of User::isValidEmailAddr(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetMagic':DEPRECATED, use $magicWords in a file listed in $wgExtensionMessagesFiles instead. Use this to define synonyms of magic words depending of the language $magicExtensions:associative array of magic words synonyms $lang:language code(string) 'LanguageGetSpecialPageAliases':DEPRECATED, use $specialPageAliases in a file listed in $wgExtensionMessagesFiles instead. Use to define aliases of special pages names depending of the language $specialPageAliases:associative array of magic words synonyms $lang:language code(string) 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Associative array mapping language codes to prefixed links of the form "language:title". & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LinkBegin':Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1528
ID
occurs before session is loaded can be modified ID
Definition: hooks.txt:2818
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:189
of
globals txt Globals are evil The original MediaWiki code relied on globals for processing context far too often MediaWiki development since then has been a story of slowly moving context out of global variables and into objects Storing processing context in object member variables allows those objects to be reused in a much more flexible way Consider the elegance of
Definition: globals.txt:10
SpecialSearch\$mPrefix
String $mPrefix
No idea, apparently used by some other classes *.
Definition: SpecialSearch.php:46
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
SpecialSearch\formHeader
formHeader( $term, $resultsShown, $totalNum)
Definition: SpecialSearch.php:1004
SpecialSearch\$fulltext
string $fulltext
Definition: SpecialSearch.php:58
$html
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses & $html
Definition: hooks.txt:1530
Xml\tags
static tags( $element, $attribs=null, $contents)
Same as Xml::element(), but does not escape contents.
Definition: Xml.php:131
SpecialPage\getOutput
getOutput()
Get the OutputPage being used for this instance.
Definition: SpecialPage.php:535
is
We use the convention $dbr for read and $dbw for write to help you keep track of whether the database object is a the world will explode Or to be a subsequent write query which succeeded on the master may fail when replicated to the slave due to a unique key collision Replication on the slave will stop and it may take hours to repair the database and get it back online Setting read_only in my cnf on the slave will avoid this but given the dire we prefer to have as many checks as possible We provide a but the wrapper functions like please read the documentation for except in special pages derived from QueryPage It s a common pitfall for new developers to submit code containing SQL queries which examine huge numbers of rows Remember that COUNT * is(N), counting rows in atable is like counting beans in a bucket.------------------------------------------------------------------------ Replication------------------------------------------------------------------------The largest installation of MediaWiki, Wikimedia, uses a large set ofslave MySQL servers replicating writes made to a master MySQL server. Itis important to understand the issues associated with this setup if youwant to write code destined for Wikipedia.It 's often the case that the best algorithm to use for a given taskdepends on whether or not replication is in use. Due to our unabashedWikipedia-centrism, we often just use the replication-friendly version, but if you like, you can use wfGetLB() ->getServerCount() > 1 tocheck to see if replication is in use.===Lag===Lag primarily occurs when large write queries are sent to the master.Writes on the master are executed in parallel, but they are executed inserial when they are replicated to the slaves. The master writes thequery to the binlog when the transaction is committed. The slaves pollthe binlog and start executing the query as soon as it appears. They canservice reads while they are performing a write query, but will not readanything more from the binlog and thus will perform no more writes. Thismeans that if the write query runs for a long time, the slaves will lagbehind the master for the time it takes for the write query to complete.Lag can be exacerbated by high read load. MediaWiki 's load balancer willstop sending reads to a slave when it is lagged by more than 30 seconds.If the load ratios are set incorrectly, or if there is too much loadgenerally, this may lead to a slave permanently hovering around 30seconds lag.If all slaves are lagged by more than 30 seconds, MediaWiki will stopwriting to the database. All edits and other write operations will berefused, with an error returned to the user. This gives the slaves achance to catch up. Before we had this mechanism, the slaves wouldregularly lag by several minutes, making review of recent editsdifficult.In addition to this, MediaWiki attempts to ensure that the user seesevents occurring on the wiki in chronological order. A few seconds of lagcan be tolerated, as long as the user sees a consistent picture fromsubsequent requests. This is done by saving the master binlog positionin the session, and then at the start of each request, waiting for theslave to catch up to that position before doing any reads from it. Ifthis wait times out, reads are allowed anyway, but the request isconsidered to be in "lagged slave mode". Lagged slave mode can bechecked by calling wfGetLB() ->getLaggedSlaveMode(). The onlypractical consequence at present is a warning displayed in the pagefooter.===Lag avoidance===To avoid excessive lag, queries which write large numbers of rows shouldbe split up, generally to write one row at a time. Multi-row INSERT ...SELECT queries are the worst offenders should be avoided altogether.Instead do the select first and then the insert.===Working with lag===Despite our best efforts, it 's not practical to guarantee a low-lagenvironment. Lag will usually be less than one second, but mayoccasionally be up to 30 seconds. For scalability, it 's very importantto keep load on the master low, so simply sending all your queries tothe master is not the answer. So when you have a genuine need forup-to-date data, the following approach is advised:1) Do a quick query to the master for a sequence number or timestamp 2) Run the full query on the slave and check if it matches the data you gotfrom the master 3) If it doesn 't, run the full query on the masterTo avoid swamping the master every time the slaves lag, use of thisapproach should be kept to a minimum. In most cases you should just readfrom the slave and let the user deal with the delay.------------------------------------------------------------------------ Lock contention------------------------------------------------------------------------Due to the high write rate on Wikipedia(and some other wikis), MediaWiki developers need to be very careful to structure their writesto avoid long-lasting locks. By default, MediaWiki opens a transactionat the first query, and commits it before the output is sent. Locks willbe held from the time when the query is done until the commit. So youcan reduce lock time by doing as much processing as possible before youdo your write queries.Often this approach is not good enough, and it becomes necessary toenclose small groups of queries in their own transaction. Use thefollowing syntax:$dbw=wfGetDB(DB_MASTER
SpecialSearch\startsWithImage
startsWithImage( $term)
Check if query starts with image: prefix.
Definition: SpecialSearch.php:1135
SpecialSearch\$limit
int $limit
Definition: SpecialSearch.php:50
text
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the and dealing with sessions and cookies OutputPage Encapsulates the entire HTML page that will be sent in response to any server request It is used by calling its functions to add text
Definition: design.txt:12
$timestamp
if( $limit) $timestamp
Definition: importImages.php:104
$form
usually copyright or history_copyright This message must be in HTML not wikitext $subpages will be ignored and the rest of subPageSubtitle() will run. 'SkinTemplateBuildNavUrlsNav_urlsAfterPermalink' whether MediaWiki currently thinks this is a CSS JS page Hooks may change this value to override the return value of Title::isCssOrJsPage(). 'TitleIsAlwaysKnown' whether MediaWiki currently thinks this page is known isMovable() always returns false. $title whether MediaWiki currently thinks this page is movable Hooks may change this value to override the return value of Title::isMovable(). 'TitleIsWikitextPage' whether MediaWiki currently thinks this is a wikitext page Hooks may change this value to override the return value of Title::isWikitextPage() 'TitleMove' use UploadVerification and UploadVerifyFile instead $form
Definition: hooks.txt:2573
SearchEngine\searchableNamespaces
static searchableNamespaces()
Make a list of searchable namespaces and their canonical names.
Definition: SearchEngine.php:334
SpecialSearch\$extraParams
Array $extraParams
For links *.
Definition: SpecialSearch.php:44
wfDebugLog
wfDebugLog( $logGroup, $text, $dest='all')
Send a line to a supplementary debug log file, if configured, or main debug log if not.
Definition: GlobalFunctions.php:1040
$n
$n
Definition: RandomTest.php:76
NS_FILE
const NS_FILE
Definition: Defines.php:85
$params
$params
Definition: styleTest.css.php:40
SpecialSearch\startsWithAll
startsWithAll( $term)
Check if query starts with all: prefix.
Definition: SpecialSearch.php:1152
SpecialPage\getTitleFor
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name.
Definition: SpecialPage.php:74
Html\hidden
static hidden( $name, $value, $attribs=array())
Convenience function to produce an input element with type=hidden.
Definition: Html.php:662
$wgContLang
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as and the content language as $wgContLang
Definition: design.txt:56
SpecialPage\getLanguage
getLanguage()
Shortcut to get user's language.
Definition: SpecialPage.php:578
SpecialSearch\$searchEngineType
String $searchEngineType
Search engine type, if not default *.
Definition: SpecialSearch.php:42
$link
set to $title object and return false for a match for latest after cache objects are set use the ContentHandler facility to handle CSS and JavaScript for highlighting & $link
Definition: hooks.txt:2149
SearchEngine\defaultNamespaces
static defaultNamespaces()
An array of namespaces indexes to be searched by default.
Definition: SearchEngine.php:393
Xml\openElement
static openElement( $element, $attribs=null)
This opens an XML element.
Definition: Xml.php:109
SpecialSearch\setupPage
setupPage( $term)
Definition: SpecialSearch.php:462
Linker\linkKnown
static linkKnown( $target, $html=null, $customAttribs=array(), $query=array(), $options=array( 'known', 'noclasses'))
Identical to link(), except $options defaults to 'known'.
Definition: Linker.php:264
SpecialSearch\getSearchProfiles
getSearchProfiles()
Definition: SpecialSearch.php:948
SpecialSearch\showMatches
showMatches(&$matches)
Show whole set of results.
Definition: SpecialSearch.php:520
SpecialSearch\NAMESPACES_CURRENT
const NAMESPACES_CURRENT
Definition: SpecialSearch.php:60
Status
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition: Status.php:40
wfParseUrl
wfParseUrl( $url)
parse_url() work-alike, but non-broken.
Definition: GlobalFunctions.php:755
ProfileSection
Class for handling function-scope profiling.
Definition: Profiler.php:60
namespaces
to move a page</td >< td > &*You are moving the page across namespaces
Definition: All_system_messages.txt:2677
$out
$out
Definition: UtfNormalGenerate.php:167
SpecialSearch\getGroupName
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
Definition: SpecialSearch.php:1207
SpecialSearch\getProfileForm
getProfileForm( $profile, $term)
Definition: SpecialSearch.php:852
Html\element
static element( $element, $attribs=array(), $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:148
SpecialSearch\showHit
showHit( $result, $terms)
Format a single hit result.
Definition: SpecialSearch.php:548
Xml\element
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition: Xml.php:39
wfRunHooks
wfRunHooks( $event, array $args=array(), $deprecatedVersion=null)
Call hook functions defined in $wgHooks.
Definition: GlobalFunctions.php:4010
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
SpecialPage\setHeaders
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
Definition: SpecialPage.php:352
SpecialSearch\$offset
int $offset
Definition: SpecialSearch.php:50
SpecialPage\getUser
getUser()
Shortcut to get the User executing this instance.
Definition: SpecialPage.php:545
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
NS_CATEGORY
const NS_CATEGORY
Definition: Defines.php:93
SpecialSearch\__construct
__construct()
Definition: SpecialSearch.php:62
SearchEngine\helpNamespaces
static helpNamespaces()
Return the help namespaces to be shown on Special:Search.
Definition: SearchEngine.php:423
Html\input
static input( $name, $value='', $type='text', $attribs=array())
Convenience function to produce an "<input>" element.
Definition: Html.php:645
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
Category\newFromTitle
static newFromTitle( $title)
Factory function.
Definition: Category.php:134
$section
$section
Definition: Utf8Test.php:88
SpecialSearch\$searchEngine
SearchEngine $searchEngine
Search engine *.
Definition: SpecialSearch.php:40
$line
$line
Definition: cdb.php:57
SpecialSearch\execute
execute( $par)
Entry point.
Definition: SpecialSearch.php:71
$title
presenting them properly to the user as errors is done by the caller $title
Definition: hooks.txt:1324
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:336
$matches
if(!defined( 'MEDIAWIKI')) if(!isset( $wgVersion)) $matches
Definition: NoLocalSettings.php:33
$size
$size
Definition: RandomTest.php:75
$value
$value
Definition: styleTest.css.php:45
SearchResultTooMany
Definition: SearchEngine.php:565
SpecialPage\msg
msg()
Wrapper around wfMessage that sets the current context.
Definition: SpecialPage.php:609
SpecialPage
Parent class for all special pages.
Definition: SpecialPage.php:33
SpecialSearch
implements Special:Search - Run text & title search and display the output
Definition: SpecialSearch.php:30
SpecialPage\getRequest
getRequest()
Get the WebRequest being used for this instance.
Definition: SpecialPage.php:525
SpecialSearch\$profile
null string $profile
Current search profile.
Definition: SpecialSearch.php:38
SpecialSearch\powerSearch
powerSearch(&$request)
Extract "power search" namespace settings from the request object, returning a list of index numbers ...
Definition: SpecialSearch.php:484
wfEscapeWikiText
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
Definition: GlobalFunctions.php:2077
SpecialSearch\getProfile
getProfile()
Current search profile.
Definition: SpecialSearch.php:1182
SpecialSearch\makeSearchLink
makeSearchLink( $term, $namespaces, $label, $tooltip, $params=array())
Make a search link with some target namespaces.
Definition: SpecialSearch.php:1105
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:237
SearchEngine
Contain a class for special pages.
Definition: SearchEngine.php:32
it
=Architecture==Two class hierarchies are used to provide the functionality associated with the different content models:*Content interface(and AbstractContent base class) define functionality that acts on the concrete content of a page, and *ContentHandler base class provides functionality specific to a content model, but not acting on concrete content. The most important function of ContentHandler is to act as a factory for the appropriate implementation of Content. These Content objects are to be used by MediaWiki everywhere, instead of passing page content around as text. All manipulation and analysis of page content must be done via the appropriate methods of the Content object. For each content model, a subclass of ContentHandler has to be registered with $wgContentHandlers. The ContentHandler object for a given content model can be obtained using ContentHandler::getForModelID($id). Also Title, WikiPage and Revision now have getContentHandler() methods for convenience. ContentHandler objects are singletons that provide functionality specific to the content type, but not directly acting on the content of some page. ContentHandler::makeEmptyContent() and ContentHandler::unserializeContent() can be used to create a Content object of the appropriate type. However, it is recommended to instead use WikiPage::getContent() resp. Revision::getContent() to get a page 's content as a Content object. These two methods should be the ONLY way in which page content is accessed. Another important function of ContentHandler objects is to define custom action handlers for a content model, see ContentHandler::getActionOverrides(). This is similar to what WikiPage::getActionOverrides() was already doing.==Serialization==With the ContentHandler facility, page content no longer has to be text based. Objects implementing the Content interface are used to represent and handle the content internally. For storage and data exchange, each content model supports at least one serialization format via ContentHandler::serializeContent($content). The list of supported formats for a given content model can be accessed using ContentHandler::getSupportedFormats(). Content serialization formats are identified using MIME type like strings. The following formats are built in:*text/x-wiki - wikitext *text/javascript - for js pages *text/css - for css pages *text/plain - for future use, e.g. with plain text messages. *text/html - for future use, e.g. with plain html messages. *application/vnd.php.serialized - for future use with the api and for extensions *application/json - for future use with the api, and for use by extensions *application/xml - for future use with the api, and for use by extensions In PHP, use the corresponding CONTENT_FORMAT_XXX constant. Note that when using the API to access page content, especially action=edit, action=parse and action=query &prop=revisions, the model and format of the content should always be handled explicitly. Without that information, interpretation of the provided content is not reliable. The same applies to XML dumps generated via maintenance/dumpBackup.php or Special:Export. Also note that the API will provide encapsulated, serialized content - so if the API was called with format=json, and contentformat is also json(or rather, application/json), the page content is represented as a string containing an escaped json structure. Extensions that use JSON to serialize some types of page content may provide specialized API modules that allow access to that content in a more natural form.==Compatibility==The ContentHandler facility is introduced in a way that should allow all existing code to keep functioning at least for pages that contain wikitext or other text based content. However, a number of functions and hooks have been deprecated in favor of new versions that are aware of the page 's content model, and will now generate warnings when used. Most importantly, the following functions have been deprecated:*Revisions::getText() and Revisions::getRawText() is deprecated in favor Revisions::getContent() *WikiPage::getText() is deprecated in favor WikiPage::getContent() Also, the old Article::getContent()(which returns text) is superceded by Article::getContentObject(). However, both methods should be avoided since they do not provide clean access to the page 's actual content. For instance, they may return a system message for non-existing pages. Use WikiPage::getContent() instead. Code that relies on a textual representation of the page content should eventually be rewritten. However, ContentHandler::getContentText() provides a stop-gap that can be used to get text for a page. Its behavior is controlled by $wgContentHandlerTextFallback it
Definition: contenthandler.txt:107
SpecialSearch\powerSearchOptions
powerSearchOptions()
Reconstruct the 'power search' options for links.
Definition: SpecialSearch.php:500
SpecialSearch\goResult
goResult( $term)
If an exact title match can be found, jump straight ahead to it.
Definition: SpecialSearch.php:159
SpecialSearch\$namespaces
array $namespaces
Definition: SpecialSearch.php:54
SearchEngine\getNearMatch
static getNearMatch( $searchterm)
If an exact title match can be found, or a very slightly close match, return the title.
Definition: SearchEngine.php:122
Xml\closeElement
static closeElement( $element)
Shortcut to close an XML element.
Definition: Xml.php:118
SpecialSearch\getSearchEngine
getSearchEngine()
Definition: SpecialSearch.php:1169
$term
the value to return A Title object or null whereas SearchGetNearMatch runs after $term
Definition: hooks.txt:2125
SpecialSearch\setExtraParam
setExtraParam( $key, $value)
Users of hook SpecialSearchSetupEngine can use this to add more params to links to not lose selection...
Definition: SpecialSearch.php:1203
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
SpecialSearch\load
load()
Set up basic search parameters from the request and user settings.
Definition: SpecialSearch.php:107
wfFindFile
wfFindFile( $title, $options=array())
Find a file.
Definition: GlobalFunctions.php:3702
SpecialSearch\powerSearchBox
powerSearchBox( $term, $opts)
Generates the power search box at [[Special:Search]].
Definition: SpecialSearch.php:874
SpecialSearch\shortDialog
shortDialog( $term)
Definition: SpecialSearch.php:1076
SpecialSearch\showCreateLink
showCreateLink( $title, $num, $titleMatches, $textMatches)
Definition: SpecialSearch.php:425
Xml\submitButton
static submitButton( $value, $attribs=array())
Convenience function to build an HTML submit button.
Definition: Xml.php:463
name
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at name
Definition: design.txt:12
$query
return true to allow those checks to and false if checking is done use this to change the tables headers temp or archived zone change it to an object instance and return false override the list derivative used the name of the old file when set the default code will be skipped add a value to it if you want to add a cookie that have to vary cache options can modify $query
Definition: hooks.txt:1105
SpecialSearch\$didYouMeanHtml
string $didYouMeanHtml
Definition: SpecialSearch.php:58
SpecialSearch\showInterwiki
showInterwiki( $matches, $query)
Show results from other wikis.
Definition: SpecialSearch.php:728
MWNamespace\getSubject
static getSubject( $index)
Get the subject namespace index for a given namespace Special namespaces (NS_MEDIA,...
Definition: Namespace.php:132
SpecialSearch\showResults
showResults( $term)
Definition: SpecialSearch.php:202
SpecialPage\outputHeader
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
Definition: SpecialPage.php:443
SearchEngine\create
static create( $type=null)
Load up the appropriate search engine class for the currently active database backend,...
Definition: SearchEngine.php:447
SearchEngine\namespacesAsText
static namespacesAsText( $namespaces)
Get a list of namespace names useful for showing in tooltips and preferences.
Definition: SearchEngine.php:406
SearchEngine\userNamespaces
static userNamespaces( $user)
Extract default namespaces to search from the given user's settings, returning a list of index number...
Definition: SearchEngine.php:354
SpecialSearch\showInterwikiHit
showInterwikiHit( $result, $lastInterwiki, $query, $customCaptions)
Show single interwiki link.
Definition: SpecialSearch.php:780