MediaWiki REL1_39
SearchNearMatcher.php
Go to the documentation of this file.
1<?php
2
9
18 protected $config;
19
24 private $language;
25
30 private $languageConverter;
31
35 private $hookRunner;
36
40 private $wikiPageFactory;
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
Base class for language-specific code.
Definition Language.php:53
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
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.
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.
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,...
Interface for configuration instances.
Definition Config.php:30
The shared interface for all language converters.
if(!isset( $args[0])) $lang