Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like SpecialSearch often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use SpecialSearch, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 32 | class SpecialSearch extends SpecialPage { |
||
| 33 | /** |
||
| 34 | * Current search profile. Search profile is just a name that identifies |
||
| 35 | * the active search tab on the search page (content, discussions...) |
||
| 36 | * For users tt replaces the set of enabled namespaces from the query |
||
| 37 | * string when applicable. Extensions can add new profiles with hooks |
||
| 38 | * with custom search options just for that profile. |
||
| 39 | * @var null|string |
||
| 40 | */ |
||
| 41 | protected $profile; |
||
| 42 | |||
| 43 | /** @var SearchEngine Search engine */ |
||
| 44 | protected $searchEngine; |
||
| 45 | |||
| 46 | /** @var string Search engine type, if not default */ |
||
| 47 | protected $searchEngineType; |
||
| 48 | |||
| 49 | /** @var array For links */ |
||
| 50 | protected $extraParams = []; |
||
| 51 | |||
| 52 | /** |
||
| 53 | * @var string The prefix url parameter. Set on the searcher and the |
||
| 54 | * is expected to treat it as prefix filter on titles. |
||
| 55 | */ |
||
| 56 | protected $mPrefix; |
||
| 57 | |||
| 58 | /** |
||
| 59 | * @var int |
||
| 60 | */ |
||
| 61 | protected $limit, $offset; |
||
|
|
|||
| 62 | |||
| 63 | /** |
||
| 64 | * @var array |
||
| 65 | */ |
||
| 66 | protected $namespaces; |
||
| 67 | |||
| 68 | /** |
||
| 69 | * @var string |
||
| 70 | */ |
||
| 71 | protected $fulltext; |
||
| 72 | |||
| 73 | /** |
||
| 74 | * @var bool |
||
| 75 | */ |
||
| 76 | protected $runSuggestion = true; |
||
| 77 | |||
| 78 | /** |
||
| 79 | * Names of the wikis, in format: Interwiki prefix -> caption |
||
| 80 | * @var array |
||
| 81 | */ |
||
| 82 | protected $customCaptions; |
||
| 83 | |||
| 84 | /** |
||
| 85 | * Search engine configurations. |
||
| 86 | * @var SearchEngineConfig |
||
| 87 | */ |
||
| 88 | protected $searchConfig; |
||
| 89 | |||
| 90 | const NAMESPACES_CURRENT = 'sense'; |
||
| 91 | |||
| 92 | public function __construct() { |
||
| 96 | |||
| 97 | /** |
||
| 98 | * Entry point |
||
| 99 | * |
||
| 100 | * @param string $par |
||
| 101 | */ |
||
| 102 | public function execute( $par ) { |
||
| 103 | $request = $this->getRequest(); |
||
| 104 | |||
| 105 | // Fetch the search term |
||
| 106 | $search = str_replace( "\n", " ", $request->getText( 'search' ) ); |
||
| 107 | |||
| 108 | // Historically search terms have been accepted not only in the search query |
||
| 109 | // parameter, but also as part of the primary url. This can have PII implications |
||
| 110 | // in releasing page view data. As such issue a 301 redirect to the correct |
||
| 111 | // URL. |
||
| 112 | if ( strlen( $par ) && !strlen( $search ) ) { |
||
| 113 | $query = $request->getValues(); |
||
| 114 | unset( $query['title'] ); |
||
| 115 | // Strip underscores from title parameter; most of the time we'll want |
||
| 116 | // text form here. But don't strip underscores from actual text params! |
||
| 117 | $query['search'] = str_replace( '_', ' ', $par ); |
||
| 118 | $this->getOutput()->redirect( $this->getPageTitle()->getFullURL( $query ), 301 ); |
||
| 119 | return; |
||
| 120 | } |
||
| 121 | |||
| 122 | $this->setHeaders(); |
||
| 123 | $this->outputHeader(); |
||
| 124 | $out = $this->getOutput(); |
||
| 125 | $out->allowClickjacking(); |
||
| 126 | $out->addModuleStyles( [ |
||
| 127 | 'mediawiki.special', 'mediawiki.special.search.styles', 'mediawiki.ui', 'mediawiki.ui.button', |
||
| 128 | 'mediawiki.ui.input', 'mediawiki.widgets.SearchInputWidget.styles', |
||
| 129 | ] ); |
||
| 130 | $this->addHelpLink( 'Help:Searching' ); |
||
| 131 | |||
| 132 | $this->load(); |
||
| 133 | if ( !is_null( $request->getVal( 'nsRemember' ) ) ) { |
||
| 134 | $this->saveNamespaces(); |
||
| 135 | // Remove the token from the URL to prevent the user from inadvertently |
||
| 136 | // exposing it (e.g. by pasting it into a public wiki page) or undoing |
||
| 137 | // later settings changes (e.g. by reloading the page). |
||
| 138 | $query = $request->getValues(); |
||
| 139 | unset( $query['title'], $query['nsRemember'] ); |
||
| 140 | $out->redirect( $this->getPageTitle()->getFullURL( $query ) ); |
||
| 141 | return; |
||
| 142 | } |
||
| 143 | |||
| 144 | $out->addJsConfigVars( [ 'searchTerm' => $search ] ); |
||
| 145 | $this->searchEngineType = $request->getVal( 'srbackend' ); |
||
| 146 | |||
| 147 | if ( $request->getVal( 'fulltext' ) |
||
| 148 | || !is_null( $request->getVal( 'offset' ) ) |
||
| 149 | ) { |
||
| 150 | $this->showResults( $search ); |
||
| 151 | } else { |
||
| 152 | $this->goResult( $search ); |
||
| 153 | } |
||
| 154 | } |
||
| 155 | |||
| 156 | /** |
||
| 157 | * Set up basic search parameters from the request and user settings. |
||
| 158 | * |
||
| 159 | * @see tests/phpunit/includes/specials/SpecialSearchTest.php |
||
| 160 | */ |
||
| 161 | public function load() { |
||
| 207 | |||
| 208 | /** |
||
| 209 | * If an exact title match can be found, jump straight ahead to it. |
||
| 210 | * |
||
| 211 | * @param string $term |
||
| 212 | */ |
||
| 213 | public function goResult( $term ) { |
||
| 214 | $this->setupPage( $term ); |
||
| 215 | # Try to go to page as entered. |
||
| 216 | $title = Title::newFromText( $term ); |
||
| 217 | # If the string cannot be used to create a title |
||
| 218 | if ( is_null( $title ) ) { |
||
| 219 | $this->showResults( $term ); |
||
| 220 | |||
| 221 | return; |
||
| 222 | } |
||
| 223 | # If there's an exact or very near match, jump right there. |
||
| 224 | $title = $this->getSearchEngine() |
||
| 225 | ->getNearMatcher( $this->getConfig() )->getNearMatch( $term ); |
||
| 226 | |||
| 227 | if ( !is_null( $title ) && |
||
| 228 | Hooks::run( 'SpecialSearchGoResult', [ $term, $title, &$url ] ) |
||
| 229 | ) { |
||
| 230 | if ( $url === null ) { |
||
| 231 | $url = $title->getFullURL(); |
||
| 232 | } |
||
| 233 | $this->getOutput()->redirect( $url ); |
||
| 234 | |||
| 235 | return; |
||
| 236 | } |
||
| 237 | $this->showResults( $term ); |
||
| 238 | } |
||
| 239 | |||
| 240 | /** |
||
| 241 | * @param string $term |
||
| 242 | */ |
||
| 243 | public function showResults( $term ) { |
||
| 244 | global $wgContLang; |
||
| 245 | |||
| 246 | $search = $this->getSearchEngine(); |
||
| 247 | $search->setFeatureData( 'rewrite', $this->runSuggestion ); |
||
| 248 | $search->setLimitOffset( $this->limit, $this->offset ); |
||
| 249 | $search->setNamespaces( $this->namespaces ); |
||
| 250 | $search->prefix = $this->mPrefix; |
||
| 251 | $term = $search->transformSearchTerm( $term ); |
||
| 252 | |||
| 253 | Hooks::run( 'SpecialSearchSetupEngine', [ $this, $this->profile, $search ] ); |
||
| 254 | |||
| 255 | $this->setupPage( $term ); |
||
| 256 | |||
| 257 | $out = $this->getOutput(); |
||
| 258 | |||
| 259 | if ( $this->getConfig()->get( 'DisableTextSearch' ) ) { |
||
| 260 | $searchFowardUrl = $this->getConfig()->get( 'SearchForwardUrl' ); |
||
| 261 | if ( $searchFowardUrl ) { |
||
| 262 | $url = str_replace( '$1', urlencode( $term ), $searchFowardUrl ); |
||
| 263 | $out->redirect( $url ); |
||
| 264 | } else { |
||
| 265 | $out->addHTML( |
||
| 266 | Xml::openElement( 'fieldset' ) . |
||
| 267 | Xml::element( 'legend', null, $this->msg( 'search-external' )->text() ) . |
||
| 268 | Xml::element( |
||
| 269 | 'p', |
||
| 270 | [ 'class' => 'mw-searchdisabled' ], |
||
| 271 | $this->msg( 'searchdisabled' )->text() |
||
| 272 | ) . |
||
| 273 | $this->msg( 'googlesearch' )->rawParams( |
||
| 274 | htmlspecialchars( $term ), |
||
| 275 | 'UTF-8', |
||
| 276 | $this->msg( 'searchbutton' )->escaped() |
||
| 277 | )->text() . |
||
| 278 | Xml::closeElement( 'fieldset' ) |
||
| 279 | ); |
||
| 280 | } |
||
| 281 | |||
| 282 | return; |
||
| 283 | } |
||
| 284 | |||
| 285 | $title = Title::newFromText( $term ); |
||
| 286 | $showSuggestion = $title === null || !$title->isKnown(); |
||
| 287 | $search->setShowSuggestion( $showSuggestion ); |
||
| 288 | |||
| 289 | // fetch search results |
||
| 290 | $rewritten = $search->replacePrefixes( $term ); |
||
| 291 | |||
| 292 | $titleMatches = $search->searchTitle( $rewritten ); |
||
| 293 | $textMatches = $search->searchText( $rewritten ); |
||
| 294 | |||
| 295 | $textStatus = null; |
||
| 296 | if ( $textMatches instanceof Status ) { |
||
| 297 | $textStatus = $textMatches; |
||
| 298 | $textMatches = null; |
||
| 299 | } |
||
| 300 | |||
| 301 | // did you mean... suggestions |
||
| 302 | $didYouMeanHtml = ''; |
||
| 303 | if ( $showSuggestion && $textMatches && !$textStatus ) { |
||
| 304 | if ( $textMatches->hasRewrittenQuery() ) { |
||
| 305 | $didYouMeanHtml = $this->getDidYouMeanRewrittenHtml( $term, $textMatches ); |
||
| 306 | } elseif ( $textMatches->hasSuggestion() ) { |
||
| 307 | $didYouMeanHtml = $this->getDidYouMeanHtml( $textMatches ); |
||
| 308 | } |
||
| 309 | } |
||
| 310 | |||
| 311 | if ( !Hooks::run( 'SpecialSearchResultsPrepend', [ $this, $out, $term ] ) ) { |
||
| 312 | # Hook requested termination |
||
| 313 | return; |
||
| 314 | } |
||
| 315 | |||
| 316 | // start rendering the page |
||
| 317 | $out->addHTML( |
||
| 318 | Xml::openElement( |
||
| 319 | 'form', |
||
| 320 | [ |
||
| 321 | 'id' => ( $this->isPowerSearch() ? 'powersearch' : 'search' ), |
||
| 322 | 'method' => 'get', |
||
| 323 | 'action' => wfScript(), |
||
| 324 | ] |
||
| 325 | ) |
||
| 326 | ); |
||
| 327 | |||
| 328 | // Get number of results |
||
| 329 | $titleMatchesNum = $textMatchesNum = $numTitleMatches = $numTextMatches = 0; |
||
| 330 | if ( $titleMatches ) { |
||
| 331 | $titleMatchesNum = $titleMatches->numRows(); |
||
| 332 | $numTitleMatches = $titleMatches->getTotalHits(); |
||
| 333 | } |
||
| 334 | if ( $textMatches ) { |
||
| 335 | $textMatchesNum = $textMatches->numRows(); |
||
| 336 | $numTextMatches = $textMatches->getTotalHits(); |
||
| 337 | } |
||
| 338 | $num = $titleMatchesNum + $textMatchesNum; |
||
| 339 | $totalRes = $numTitleMatches + $numTextMatches; |
||
| 340 | |||
| 341 | $out->enableOOUI(); |
||
| 342 | $out->addHTML( |
||
| 343 | # This is an awful awful ID name. It's not a table, but we |
||
| 344 | # named it poorly from when this was a table so now we're |
||
| 345 | # stuck with it |
||
| 346 | Xml::openElement( 'div', [ 'id' => 'mw-search-top-table' ] ) . |
||
| 347 | $this->shortDialog( $term, $num, $totalRes ) . |
||
| 348 | Xml::closeElement( 'div' ) . |
||
| 349 | $this->searchProfileTabs( $term ) . |
||
| 350 | $this->searchOptions( $term ) . |
||
| 351 | Xml::closeElement( 'form' ) . |
||
| 352 | $didYouMeanHtml |
||
| 353 | ); |
||
| 354 | |||
| 355 | $filePrefix = $wgContLang->getFormattedNsText( NS_FILE ) . ':'; |
||
| 356 | if ( trim( $term ) === '' || $filePrefix === trim( $term ) ) { |
||
| 357 | // Empty query -- straight view of search form |
||
| 358 | return; |
||
| 359 | } |
||
| 360 | |||
| 361 | $out->addHTML( "<div class='searchresults'>" ); |
||
| 362 | |||
| 363 | // prev/next links |
||
| 364 | $prevnext = null; |
||
| 365 | if ( $num || $this->offset ) { |
||
| 366 | // Show the create link ahead |
||
| 367 | $this->showCreateLink( $title, $num, $titleMatches, $textMatches ); |
||
| 368 | if ( $totalRes > $this->limit || $this->offset ) { |
||
| 369 | if ( $this->searchEngineType !== null ) { |
||
| 370 | $this->setExtraParam( 'srbackend', $this->searchEngineType ); |
||
| 371 | } |
||
| 372 | $prevnext = $this->getLanguage()->viewPrevNext( |
||
| 373 | $this->getPageTitle(), |
||
| 374 | $this->offset, |
||
| 375 | $this->limit, |
||
| 376 | $this->powerSearchOptions() + [ 'search' => $term ], |
||
| 377 | $this->limit + $this->offset >= $totalRes |
||
| 378 | ); |
||
| 379 | } |
||
| 380 | } |
||
| 381 | Hooks::run( 'SpecialSearchResults', [ $term, &$titleMatches, &$textMatches ] ); |
||
| 382 | |||
| 383 | $out->parserOptions()->setEditSection( false ); |
||
| 384 | if ( $titleMatches ) { |
||
| 385 | if ( $numTitleMatches > 0 ) { |
||
| 386 | $out->wrapWikiMsg( "==$1==\n", 'titlematches' ); |
||
| 387 | $out->addHTML( $this->showMatches( $titleMatches ) ); |
||
| 388 | } |
||
| 389 | $titleMatches->free(); |
||
| 390 | } |
||
| 391 | if ( $textMatches && !$textStatus ) { |
||
| 392 | // output appropriate heading |
||
| 393 | if ( $numTextMatches > 0 && $numTitleMatches > 0 ) { |
||
| 394 | $out->addHTML( '<div class="mw-search-visualclear"></div>' ); |
||
| 395 | // if no title matches the heading is redundant |
||
| 396 | $out->wrapWikiMsg( "==$1==\n", 'textmatches' ); |
||
| 397 | } |
||
| 398 | |||
| 399 | // show results |
||
| 400 | if ( $numTextMatches > 0 ) { |
||
| 401 | $search->augmentSearchResults( $textMatches ); |
||
| 402 | $out->addHTML( $this->showMatches( $textMatches ) ); |
||
| 403 | } |
||
| 404 | |||
| 405 | // show secondary interwiki results if any |
||
| 406 | if ( $textMatches->hasInterwikiResults( SearchResultSet::SECONDARY_RESULTS ) ) { |
||
| 407 | $out->addHTML( $this->showInterwiki( $textMatches->getInterwikiResults( |
||
| 408 | SearchResultSet::SECONDARY_RESULTS ), $term ) ); |
||
| 409 | } |
||
| 410 | } |
||
| 411 | |||
| 412 | $hasOtherResults = $textMatches && |
||
| 413 | $textMatches->hasInterwikiResults( SearchResultSet::INLINE_RESULTS ); |
||
| 414 | |||
| 415 | if ( $num === 0 ) { |
||
| 416 | if ( $textStatus ) { |
||
| 417 | $out->addHTML( '<div class="error">' . |
||
| 418 | $textStatus->getMessage( 'search-error' ) . '</div>' ); |
||
| 419 | } else { |
||
| 420 | if ( !$this->offset ) { |
||
| 421 | // If we have an offset the create link was rendered earlier in this function. |
||
| 422 | // This class needs a good de-spaghettification, but for now this will |
||
| 423 | // do the job. |
||
| 424 | $this->showCreateLink( $title, $num, $titleMatches, $textMatches ); |
||
| 425 | } |
||
| 426 | $out->wrapWikiMsg( "<p class=\"mw-search-nonefound\">\n$1</p>", |
||
| 427 | [ $hasOtherResults ? 'search-nonefound-thiswiki' : 'search-nonefound', |
||
| 428 | wfEscapeWikiText( $term ) |
||
| 429 | ] ); |
||
| 430 | } |
||
| 431 | } |
||
| 432 | |||
| 433 | if ( $hasOtherResults ) { |
||
| 434 | foreach ( $textMatches->getInterwikiResults( SearchResultSet::INLINE_RESULTS ) |
||
| 435 | as $interwiki => $interwikiResult ) { |
||
| 436 | if ( $interwikiResult instanceof Status || $interwikiResult->numRows() == 0 ) { |
||
| 437 | // ignore bad interwikis for now |
||
| 438 | continue; |
||
| 439 | } |
||
| 440 | // TODO: wiki header |
||
| 441 | $out->addHTML( $this->showMatches( $interwikiResult, $interwiki ) ); |
||
| 442 | } |
||
| 443 | } |
||
| 444 | |||
| 445 | if ( $textMatches ) { |
||
| 446 | $textMatches->free(); |
||
| 447 | } |
||
| 448 | |||
| 449 | $out->addHTML( '<div class="mw-search-visualclear"></div>' ); |
||
| 450 | |||
| 451 | if ( $prevnext ) { |
||
| 452 | $out->addHTML( "<p class='mw-search-pager-bottom'>{$prevnext}</p>\n" ); |
||
| 453 | } |
||
| 454 | |||
| 455 | $out->addHTML( "</div>" ); |
||
| 456 | |||
| 457 | Hooks::run( 'SpecialSearchResultsAppend', [ $this, $out, $term ] ); |
||
| 458 | } |
||
| 459 | |||
| 460 | /** |
||
| 461 | * Produce wiki header for interwiki results |
||
| 462 | * @param string $interwiki Interwiki name |
||
| 463 | * @param SearchResultSet $interwikiResult The result set |
||
| 464 | * @return string |
||
| 465 | */ |
||
| 466 | protected function interwikiHeader( $interwiki, $interwikiResult ) { |
||
| 471 | |||
| 472 | /** |
||
| 473 | * Generates HTML shown to the user when we have a suggestion about a query |
||
| 474 | * that might give more results than their current query. |
||
| 475 | */ |
||
| 476 | protected function getDidYouMeanHtml( SearchResultSet $textMatches ) { |
||
| 500 | |||
| 501 | /** |
||
| 502 | * Generates HTML shown to user when their query has been internally rewritten, |
||
| 503 | * and the results of the rewritten query are being returned. |
||
| 504 | * |
||
| 505 | * @param string $term The users search input |
||
| 506 | * @param SearchResultSet $textMatches The response to the users initial search request |
||
| 507 | * @return string HTML linking the user to their original $term query, and the one |
||
| 508 | * suggested by $textMatches. |
||
| 509 | */ |
||
| 510 | protected function getDidYouMeanRewrittenHtml( $term, SearchResultSet $textMatches ) { |
||
| 544 | |||
| 545 | /** |
||
| 546 | * @param Title $title |
||
| 547 | * @param int $num The number of search results found |
||
| 548 | * @param null|SearchResultSet $titleMatches Results from title search |
||
| 549 | * @param null|SearchResultSet $textMatches Results from text search |
||
| 550 | */ |
||
| 551 | protected function showCreateLink( $title, $num, $titleMatches, $textMatches ) { |
||
| 593 | |||
| 594 | /** |
||
| 595 | * @param string $term |
||
| 596 | */ |
||
| 597 | protected function setupPage( $term ) { |
||
| 609 | |||
| 610 | /** |
||
| 611 | * Return true if current search is a power (advanced) search |
||
| 612 | * |
||
| 613 | * @return bool |
||
| 614 | */ |
||
| 615 | protected function isPowerSearch() { |
||
| 618 | |||
| 619 | /** |
||
| 620 | * Extract "power search" namespace settings from the request object, |
||
| 621 | * returning a list of index numbers to search. |
||
| 622 | * |
||
| 623 | * @param WebRequest $request |
||
| 624 | * @return array |
||
| 625 | */ |
||
| 626 | protected function powerSearch( &$request ) { |
||
| 636 | |||
| 637 | /** |
||
| 638 | * Reconstruct the 'power search' options for links |
||
| 639 | * |
||
| 640 | * @return array |
||
| 641 | */ |
||
| 642 | protected function powerSearchOptions() { |
||
| 654 | |||
| 655 | /** |
||
| 656 | * Save namespace preferences when we're supposed to |
||
| 657 | * |
||
| 658 | * @return bool Whether we wrote something |
||
| 659 | */ |
||
| 660 | protected function saveNamespaces() { |
||
| 691 | |||
| 692 | /** |
||
| 693 | * Show whole set of results |
||
| 694 | * |
||
| 695 | * @param SearchResultSet $matches |
||
| 696 | * @param string $interwiki Interwiki name |
||
| 697 | * |
||
| 698 | * @return string |
||
| 699 | */ |
||
| 700 | protected function showMatches( $matches, $interwiki = null ) { |
||
| 724 | |||
| 725 | /** |
||
| 726 | * Format a single hit result |
||
| 727 | * |
||
| 728 | * @param SearchResult $result |
||
| 729 | * @param array $terms Terms to highlight |
||
| 730 | * @param int $position Position within the search results, including offset. |
||
| 731 | * |
||
| 732 | * @return string |
||
| 733 | */ |
||
| 734 | protected function showHit( SearchResult $result, $terms, $position ) { |
||
| 885 | |||
| 886 | /** |
||
| 887 | * Extract custom captions from search-interwiki-custom message |
||
| 888 | */ |
||
| 889 | protected function getCustomCaptions() { |
||
| 902 | |||
| 903 | /** |
||
| 904 | * Show results from other wikis |
||
| 905 | * |
||
| 906 | * @param SearchResultSet|array $matches |
||
| 907 | * @param string $query |
||
| 908 | * |
||
| 909 | * @return string |
||
| 910 | */ |
||
| 911 | protected function showInterwiki( $matches, $query ) { |
||
| 943 | |||
| 944 | /** |
||
| 945 | * Show single interwiki link |
||
| 946 | * |
||
| 947 | * @param SearchResult $result |
||
| 948 | * @param string $lastInterwiki |
||
| 949 | * @param string $query |
||
| 950 | * |
||
| 951 | * @return string |
||
| 952 | */ |
||
| 953 | protected function showInterwikiHit( $result, $lastInterwiki, $query ) { |
||
| 1017 | |||
| 1018 | /** |
||
| 1019 | * Generates the power search box at [[Special:Search]] |
||
| 1020 | * |
||
| 1021 | * @param string $term Search term |
||
| 1022 | * @param array $opts |
||
| 1023 | * @return string HTML form |
||
| 1024 | */ |
||
| 1025 | protected function powerSearchBox( $term, $opts ) { |
||
| 1107 | |||
| 1108 | /** |
||
| 1109 | * @return array |
||
| 1110 | */ |
||
| 1111 | protected function getSearchProfiles() { |
||
| 1152 | |||
| 1153 | /** |
||
| 1154 | * @param string $term |
||
| 1155 | * @return string |
||
| 1156 | */ |
||
| 1157 | protected function searchProfileTabs( $term ) { |
||
| 1202 | |||
| 1203 | /** |
||
| 1204 | * @param string $term Search term |
||
| 1205 | * @return string |
||
| 1206 | */ |
||
| 1207 | protected function searchOptions( $term ) { |
||
| 1222 | |||
| 1223 | /** |
||
| 1224 | * @param string $term |
||
| 1225 | * @param int $resultsShown |
||
| 1226 | * @param int $totalNum |
||
| 1227 | * @return string |
||
| 1228 | */ |
||
| 1229 | protected function shortDialog( $term, $resultsShown, $totalNum ) { |
||
| 1264 | |||
| 1265 | /** |
||
| 1266 | * Make a search link with some target namespaces |
||
| 1267 | * |
||
| 1268 | * @param string $term |
||
| 1269 | * @param array $namespaces Ignored |
||
| 1270 | * @param string $label Link's text |
||
| 1271 | * @param string $tooltip Link's tooltip |
||
| 1272 | * @param array $params Query string parameters |
||
| 1273 | * @return string HTML fragment |
||
| 1274 | */ |
||
| 1275 | protected function makeSearchLink( $term, $namespaces, $label, $tooltip, $params = [] ) { |
||
| 1298 | |||
| 1299 | /** |
||
| 1300 | * Check if query starts with image: prefix |
||
| 1301 | * |
||
| 1302 | * @param string $term The string to check |
||
| 1303 | * @return bool |
||
| 1304 | */ |
||
| 1305 | protected function startsWithImage( $term ) { |
||
| 1315 | |||
| 1316 | /** |
||
| 1317 | * @since 1.18 |
||
| 1318 | * |
||
| 1319 | * @return SearchEngine |
||
| 1320 | */ |
||
| 1321 | public function getSearchEngine() { |
||
| 1330 | |||
| 1331 | /** |
||
| 1332 | * Current search profile. |
||
| 1333 | * @return null|string |
||
| 1334 | */ |
||
| 1335 | function getProfile() { |
||
| 1338 | |||
| 1339 | /** |
||
| 1340 | * Current namespaces. |
||
| 1341 | * @return array |
||
| 1342 | */ |
||
| 1343 | function getNamespaces() { |
||
| 1346 | |||
| 1347 | /** |
||
| 1348 | * Users of hook SpecialSearchSetupEngine can use this to |
||
| 1349 | * add more params to links to not lose selection when |
||
| 1350 | * user navigates search results. |
||
| 1351 | * @since 1.18 |
||
| 1352 | * |
||
| 1353 | * @param string $key |
||
| 1354 | * @param mixed $value |
||
| 1355 | */ |
||
| 1356 | public function setExtraParam( $key, $value ) { |
||
| 1359 | |||
| 1360 | protected function getGroupName() { |
||
| 1363 | } |
||
| 1364 |
Only declaring a single property per statement allows you to later on add doc comments more easily.
It is also recommended by PSR2, so it is a common style that many people expect.