MediaWiki  master
SearchNearMatcher.php
Go to the documentation of this file.
1 <?php
2 
6 
15  protected $config;
16 
21  private $language;
22 
28 
32  private $hookRunner;
33 
40  public function __construct( Config $config, Language $lang, HookContainer $hookContainer ) {
41  $this->config = $config;
42  $this->language = $lang;
43  $this->languageConverter = MediaWikiServices::getInstance()->getLanguageConverterFactory()
44  ->getLanguageConverter( $lang );
45  $this->hookRunner = new HookRunner( $hookContainer );
46  }
47 
55  public function getNearMatch( $searchterm ) {
56  $title = $this->getNearMatchInternal( $searchterm );
57 
58  $this->hookRunner->onSearchGetNearMatchComplete( $searchterm, $title );
59  return $title;
60  }
61 
69  public function getNearMatchResultSet( $searchterm ) {
70  return new SearchNearMatchResultSet( $this->getNearMatch( $searchterm ) );
71  }
72 
78  protected function getNearMatchInternal( $searchterm ) {
79  $allSearchTerms = [ $searchterm ];
80 
81  if ( $this->languageConverter->hasVariants() ) {
82  $allSearchTerms = array_unique( array_merge(
83  $allSearchTerms,
84  $this->languageConverter->autoConvertToAllVariants( $searchterm )
85  ) );
86  }
87 
88  $titleResult = null;
89  if ( !$this->hookRunner->onSearchGetNearMatchBefore( $allSearchTerms, $titleResult ) ) {
90  return $titleResult;
91  }
92 
93  // Most of our handling here deals with finding a valid title for the search term,
94  // but almost anything starting with '#' is "valid" and points to Main_Page#searchterm.
95  // Rather than doing something completely wrong, do nothing.
96  if ( $searchterm === '' || $searchterm[0] === '#' ) {
97  return null;
98  }
99 
100  foreach ( $allSearchTerms as $term ) {
101  # Exact match? No need to look further.
102  $title = Title::newFromText( $term );
103  if ( $title === null ) {
104  return null;
105  }
106 
107  # Try files if searching in the Media: namespace
108  if ( $title->getNamespace() === NS_MEDIA ) {
109  $title = Title::makeTitle( NS_FILE, $title->getText() );
110  }
111 
112  if ( $title->isSpecialPage() || $title->isExternal() || $title->exists() ) {
113  return $title;
114  }
115 
116  # See if it still otherwise has content is some sane sense
117  $page = WikiPage::factory( $title );
118  if ( $page->hasViewableContent() ) {
119  return $title;
120  }
121 
122  if ( !$this->hookRunner->onSearchAfterNoDirectMatch( $term, $title ) ) {
123  return $title;
124  }
125 
126  # Now try all lower case (i.e. first letter capitalized)
127  $title = Title::newFromText( $this->language->lc( $term ) );
128  if ( $title && $title->exists() ) {
129  return $title;
130  }
131 
132  # Now try capitalized string
133  $title = Title::newFromText( $this->language->ucwords( $term ) );
134  if ( $title && $title->exists() ) {
135  return $title;
136  }
137 
138  # Now try all upper case
139  $title = Title::newFromText( $this->language->uc( $term ) );
140  if ( $title && $title->exists() ) {
141  return $title;
142  }
143 
144  # Now try Word-Caps-Breaking-At-Word-Breaks, for hyphenated names etc
145  $title = Title::newFromText( $this->language->ucwordbreaks( $term ) );
146  if ( $title && $title->exists() ) {
147  return $title;
148  }
149 
150  // Give hooks a chance at better match variants
151  $title = null;
152  if ( !$this->hookRunner->onSearchGetNearMatch( $term, $title ) ) {
153  return $title;
154  }
155  }
156 
157  $title = Title::newFromText( $searchterm );
158 
159  # Entering an IP address goes to the contributions page
160  if ( $this->config->get( 'EnableSearchContributorsByIP' ) ) {
161  if ( ( $title->getNamespace() === NS_USER && User::isIP( $title->getText() ) )
162  || User::isIP( trim( $searchterm ) ) ) {
163  return SpecialPage::getTitleFor( 'Contributions', $title->getDBkey() );
164  }
165  }
166 
167  # Entering a user goes to the user page whether it's there or not
168  if ( $title->getNamespace() === NS_USER ) {
169  return $title;
170  }
171 
172  # Go to images that exist even if there's no local page.
173  # There may have been a funny upload, or it may be on a shared
174  # file repository such as Wikimedia Commons.
175  if ( $title->getNamespace() === NS_FILE ) {
176  $image = MediaWikiServices::getInstance()->getRepoGroup()->findFile( $title );
177  if ( $image ) {
178  return $title;
179  }
180  }
181 
182  # MediaWiki namespace? Page may be "implied" if not customized.
183  # Just return it, with caps forced as the message system likes it.
184  if ( $title->getNamespace() === NS_MEDIAWIKI ) {
185  return Title::makeTitle( NS_MEDIAWIKI, $this->language->ucfirst( $title->getText() ) );
186  }
187 
188  # Quoted term? Try without the quotes...
189  $matches = [];
190  if ( preg_match( '/^"([^"]+)"$/', $searchterm, $matches ) ) {
191  return $this->getNearMatch( $matches[1] );
192  }
193 
194  return null;
195  }
196 }
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:329
SearchNearMatcher\$hookRunner
HookRunner $hookRunner
Definition: SearchNearMatcher.php:32
SearchNearMatcher\getNearMatchInternal
getNearMatchInternal( $searchterm)
Really find the title match.
Definition: SearchNearMatcher.php:78
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:154
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:37
SearchNearMatcher\$languageConverter
ILanguageConverter $languageConverter
Current language converter.
Definition: SearchNearMatcher.php:27
NS_FILE
const NS_FILE
Definition: Defines.php:75
SearchNearMatcher\getNearMatch
getNearMatch( $searchterm)
If an exact title match can be found, or a very slightly close match, return the title.
Definition: SearchNearMatcher.php:55
SpecialPage\getTitleFor
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,...
Definition: SpecialPage.php:92
Config
Interface for configuration instances.
Definition: Config.php:30
WikiPage\factory
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
Definition: WikiPage.php:156
SearchNearMatcher
Implementation of near match title search.
Definition: SearchNearMatcher.php:11
$matches
$matches
Definition: NoLocalSettings.php:24
User\isIP
static isIP( $name)
Does the string match an anonymous IP address?
Definition: User.php:948
SearchNearMatchResultSet
A ISearchResultSet wrapper for SearchNearMatcher.
Definition: SearchNearMatchResultSet.php:5
SearchNearMatcher\getNearMatchResultSet
getNearMatchResultSet( $searchterm)
Do a near match (see SearchEngine::getNearMatch) and wrap it into a ISearchResultSet.
Definition: SearchNearMatcher.php:69
$title
$title
Definition: testCompression.php:38
SearchNearMatcher\$language
Language $language
Current language.
Definition: SearchNearMatcher.php:21
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:592
ILanguageConverter
The shared interface for all language converters.
Definition: ILanguageConverter.php:28
NS_MEDIA
const NS_MEDIA
Definition: Defines.php:57
SearchNearMatcher\$config
Config $config
Definition: SearchNearMatcher.php:15
NS_USER
const NS_USER
Definition: Defines.php:71
SearchNearMatcher\__construct
__construct(Config $config, Language $lang, HookContainer $hookContainer)
SearchNearMatcher constructor.
Definition: SearchNearMatcher.php:40
MediaWiki\HookContainer\HookContainer
HookContainer class.
Definition: HookContainer.php:44
NS_MEDIAWIKI
const NS_MEDIAWIKI
Definition: Defines.php:77
MediaWiki\HookContainer\HookRunner
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
Definition: HookRunner.php:570
Language
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
Definition: Language.php:41