MediaWiki  master
SearchNearMatcher.php
Go to the documentation of this file.
1 <?php
2 
9 
18  protected $config;
19 
24  private $language;
25 
31 
35  private $hookRunner;
36 
41 
45  private $userNameUtils;
46 
52  public function __construct( Config $config, Language $lang, HookContainer $hookContainer ) {
53  $this->config = $config;
54  $this->language = $lang;
55  $services = MediaWikiServices::getInstance();
56  $this->languageConverter = $services->getLanguageConverterFactory()
57  ->getLanguageConverter( $lang );
58  $this->wikiPageFactory = $services->getWikiPageFactory();
59  $this->hookRunner = new HookRunner( $hookContainer );
60  $this->userNameUtils = $services->getUserNameUtils();
61  }
62 
70  public function getNearMatch( $searchterm ) {
71  $title = $this->getNearMatchInternal( $searchterm );
72 
73  $this->hookRunner->onSearchGetNearMatchComplete( $searchterm, $title );
74  return $title;
75  }
76 
84  public function getNearMatchResultSet( $searchterm ) {
85  return new SearchNearMatchResultSet( $this->getNearMatch( $searchterm ) );
86  }
87 
93  protected function getNearMatchInternal( $searchterm ) {
94  $allSearchTerms = [ $searchterm ];
95 
96  if ( $this->languageConverter->hasVariants() ) {
97  $allSearchTerms = array_unique( array_merge(
98  $allSearchTerms,
99  $this->languageConverter->autoConvertToAllVariants( $searchterm )
100  ) );
101  }
102 
103  $titleResult = null;
104  if ( !$this->hookRunner->onSearchGetNearMatchBefore( $allSearchTerms, $titleResult ) ) {
105  return $titleResult;
106  }
107 
108  // Most of our handling here deals with finding a valid title for the search term,
109  // but almost anything starting with '#' is "valid" and points to Main_Page#searchterm.
110  // Rather than doing something completely wrong, do nothing.
111  if ( $searchterm === '' || $searchterm[0] === '#' ) {
112  return null;
113  }
114 
115  foreach ( $allSearchTerms as $term ) {
116  # Exact match? No need to look further.
117  $title = Title::newFromText( $term );
118  if ( $title === null ) {
119  return null;
120  }
121 
122  # Try files if searching in the Media: namespace
123  if ( $title->getNamespace() === NS_MEDIA ) {
124  $title = Title::makeTitle( NS_FILE, $title->getText() );
125  }
126 
127  if ( $title->isSpecialPage() || $title->isExternal() || $title->exists() ) {
128  return $title;
129  }
130 
131  # See if it still otherwise has content is some sensible sense
132  if ( $title->canExist() ) {
133  $page = $this->wikiPageFactory->newFromTitle( $title );
134  if ( $page->hasViewableContent() ) {
135  return $title;
136  }
137  }
138 
139  if ( !$this->hookRunner->onSearchAfterNoDirectMatch( $term, $title ) ) {
140  return $title;
141  }
142 
143  # Now try all lower case (i.e. first letter capitalized)
144  $title = Title::newFromText( $this->language->lc( $term ) );
145  if ( $title && $title->exists() ) {
146  return $title;
147  }
148 
149  # Now try capitalized string
150  $title = Title::newFromText( $this->language->ucwords( $term ) );
151  if ( $title && $title->exists() ) {
152  return $title;
153  }
154 
155  # Now try all upper case
156  $title = Title::newFromText( $this->language->uc( $term ) );
157  if ( $title && $title->exists() ) {
158  return $title;
159  }
160 
161  # Now try Word-Caps-Breaking-At-Word-Breaks, for hyphenated names etc
162  $title = Title::newFromText( $this->language->ucwordbreaks( $term ) );
163  if ( $title && $title->exists() ) {
164  return $title;
165  }
166 
167  // Give hooks a chance at better match variants
168  $title = null;
169  // @phan-suppress-next-line PhanTypeMismatchArgument Type mismatch on pass-by-ref args
170  if ( !$this->hookRunner->onSearchGetNearMatch( $term, $title ) ) {
171  return $title;
172  }
173  }
174 
175  $title = Title::newFromText( $searchterm );
176 
177  # Entering an IP address goes to the contributions page
178  if ( $this->config->get( MainConfigNames::EnableSearchContributorsByIP ) ) {
179  if ( ( $title->getNamespace() === NS_USER && $this->userNameUtils->isIP( $title->getText() ) )
180  || $this->userNameUtils->isIP( trim( $searchterm ) ) ) {
181  return SpecialPage::getTitleFor( 'Contributions', $title->getDBkey() );
182  }
183  }
184 
185  # Entering a user goes to the user page whether it's there or not
186  if ( $title->getNamespace() === NS_USER ) {
187  return $title;
188  }
189 
190  # Go to images that exist even if there's no local page.
191  # There may have been a funny upload, or it may be on a shared
192  # file repository such as Wikimedia Commons.
193  if ( $title->getNamespace() === NS_FILE ) {
194  $image = MediaWikiServices::getInstance()->getRepoGroup()->findFile( $title );
195  if ( $image ) {
196  return $title;
197  }
198  }
199 
200  # MediaWiki namespace? Page may be "implied" if not customized.
201  # Just return it, with caps forced as the message system likes it.
202  if ( $title->getNamespace() === NS_MEDIAWIKI ) {
203  return Title::makeTitle( NS_MEDIAWIKI, $this->language->ucfirst( $title->getText() ) );
204  }
205 
206  # Quoted term? Try without the quotes...
207  $matches = [];
208  if ( preg_match( '/^"([^"]+)"$/', $searchterm, $matches ) ) {
209  return $this->getNearMatch( $matches[1] );
210  }
211 
212  return null;
213  }
214 }
const NS_USER
Definition: Defines.php:66
const NS_FILE
Definition: Defines.php:70
const NS_MEDIAWIKI
Definition: Defines.php:72
const NS_MEDIA
Definition: Defines.php:52
$matches
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
Definition: Language.php:45
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
Definition: HookRunner.php:562
A class containing constants representing the names of configuration variables.
MediaWikiServices is the service locator for the application scope of MediaWiki.
Service for creating WikiPage objects.
UserNameUtils service.
A ISearchResultSet wrapper for SearchNearMatcher.
Implementation of near match title search.
getNearMatch( $searchterm)
If an exact title match can be found, or a very slightly close match, return the title.
ILanguageConverter $languageConverter
Current language converter.
Language $language
Current language.
UserNameUtils $userNameUtils
getNearMatchInternal( $searchterm)
Really find the title match.
__construct(Config $config, Language $lang, HookContainer $hookContainer)
getNearMatchResultSet( $searchterm)
Do a near match (see SearchEngine::getNearMatch) and wrap it into a ISearchResultSet.
WikiPageFactory $wikiPageFactory
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:369
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:637
Interface for configuration instances.
Definition: Config.php:30
if(!isset( $args[0])) $lang