Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 141 |
|
0.00% |
0 / 10 |
CRAP | |
0.00% |
0 / 1 |
SpecialSearchWiki | |
0.00% |
0 / 141 |
|
0.00% |
0 / 10 |
702 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
getDescription | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
20 | |||
showForm | |
0.00% |
0 / 32 |
|
0.00% |
0 / 1 |
6 | |||
getLanguageOptions | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
doSearch | |
0.00% |
0 / 38 |
|
0.00% |
0 / 1 |
110 | |||
strip | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
goToWiki | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
6 | |||
getRootCode | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
showMultipleResults | |
0.00% |
0 / 25 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\WikimediaIncubator; |
4 | |
5 | use HTMLForm; |
6 | use MediaWiki\Html\Html; |
7 | use MediaWiki\Languages\LanguageFactory; |
8 | use MediaWiki\Languages\LanguageNameUtils; |
9 | use MediaWiki\SpecialPage\IncludableSpecialPage; |
10 | use MediaWiki\Title\Title; |
11 | use Xml; |
12 | |
13 | class SpecialSearchWiki extends IncludableSpecialPage { |
14 | |
15 | /** @var array[] */ |
16 | private $mProjects; |
17 | |
18 | /** @var string[] */ |
19 | private $mNamesUserLang; |
20 | |
21 | /** @var string[] */ |
22 | private $mEnglishNames; |
23 | |
24 | /** @var string[] */ |
25 | private $mNativeNames; |
26 | |
27 | /** @var LanguageNameUtils */ |
28 | private $languageNameUtils; |
29 | |
30 | /** @var LanguageFactory */ |
31 | private $languageFactory; |
32 | |
33 | /** |
34 | * @param LanguageNameUtils $languageNameUtils |
35 | * @param LanguageFactory $languageFactory |
36 | */ |
37 | public function __construct( |
38 | LanguageNameUtils $languageNameUtils, |
39 | LanguageFactory $languageFactory |
40 | ) { |
41 | parent::__construct( 'SearchWiki' ); |
42 | $this->languageNameUtils = $languageNameUtils; |
43 | $this->languageFactory = $languageFactory; |
44 | } |
45 | |
46 | public function getDescription() { |
47 | return $this->msg( 'wminc-searchwiki' ); |
48 | } |
49 | |
50 | /** |
51 | * Show the special page |
52 | * @param string|null $subpage parameter passed to the page or null |
53 | */ |
54 | public function execute( $subpage ) { |
55 | global $wmincProjects; |
56 | |
57 | $this->setHeaders(); |
58 | |
59 | # Array of projects |
60 | $this->mProjects = $wmincProjects; |
61 | |
62 | # Queries |
63 | if ( $subpage ) { |
64 | $subpage = explode( '/', $subpage ); |
65 | } |
66 | $projectQuery = $this->getRequest()->getText( 'searchproject', $subpage[0] ?? '' ); |
67 | $languageQuery = $this->getRequest()->getText( 'searchlanguage', $subpage[1] ?? '' ); |
68 | |
69 | $this->showForm( $projectQuery, $languageQuery ); |
70 | |
71 | # Search |
72 | if ( $projectQuery || $languageQuery ) { |
73 | $this->mNamesUserLang = $this->languageNameUtils |
74 | ->getLanguageNames( $this->getLanguage()->getCode(), LanguageNameUtils::ALL ); |
75 | $this->mEnglishNames = $this->languageNameUtils |
76 | ->getLanguageNames( 'en', LanguageNameUtils::ALL ); |
77 | $this->mNativeNames = $this->languageNameUtils |
78 | ->getLanguageNames( LanguageNameUtils::AUTONYMS, LanguageNameUtils::ALL ); |
79 | $this->doSearch( $projectQuery, $languageQuery ); |
80 | } |
81 | } |
82 | |
83 | /** |
84 | * Output the search form. |
85 | * @param string $project Default value for project field |
86 | * @param string $language Default value for language field |
87 | */ |
88 | protected function showForm( $project, $language ) { |
89 | $projectList = []; |
90 | foreach ( $this->mProjects as $projectCode => $projectMetadata ) { |
91 | $projectList[$projectMetadata['name']] = $projectCode; |
92 | } |
93 | |
94 | $form = HTMLForm::factory( |
95 | 'ooui', |
96 | [ |
97 | 'Project' => [ |
98 | 'type' => 'select', |
99 | 'name' => 'searchproject', |
100 | 'id' => 'wminc-searchproject', |
101 | 'options' => $projectList, |
102 | 'label-message' => 'wminc-searchwiki-selectproject', |
103 | 'default' => $project, |
104 | ], |
105 | 'Language' => [ |
106 | 'type' => 'combobox', |
107 | 'options' => $this->getLanguageOptions(), |
108 | 'name' => 'searchlanguage', |
109 | 'id' => 'wminc-searchlanguage', |
110 | 'size' => 30, |
111 | 'label-message' => 'wminc-searchwiki-inputlanguage', |
112 | 'default' => $language, |
113 | ], |
114 | ], |
115 | $this->getContext() |
116 | ); |
117 | $form->setMethod( 'get' ) |
118 | ->setWrapperLegendMsg( 'wminc-searchwiki' ) |
119 | ->setSubmitTextMsg( 'wminc-searchwiki-go' ) |
120 | ->setId( 'wminc-searchwiki-form' ) |
121 | ->prepareForm() |
122 | ->displayForm( false ); |
123 | } |
124 | |
125 | /** |
126 | * Get a list of supported languages for use by the language form field. |
127 | * Code stolen from SpecialPageLanguage |
128 | * |
129 | * @return array |
130 | */ |
131 | private function getLanguageOptions() { |
132 | $userLang = $this->getLanguage()->getCode(); |
133 | $languages = $this->languageNameUtils->getLanguageNames( $userLang, LanguageNameUtils::SUPPORTED ); |
134 | ksort( $languages ); |
135 | $options = []; |
136 | foreach ( $languages as $code => $name ) { |
137 | $options["$code - $name"] = $name; |
138 | } |
139 | return $options; |
140 | } |
141 | |
142 | /** |
143 | * @param string $projectQuery |
144 | * @param string $languageQuery |
145 | */ |
146 | protected function doSearch( $projectQuery, $languageQuery ) { |
147 | ## Match project ## |
148 | if ( isset( $this->mProjects[$projectQuery] ) ) { |
149 | # searched with a project code (select box) |
150 | $matchProject = $projectQuery; |
151 | } else { |
152 | $projectCode = array_search( $projectQuery, array_column( $this->mProjects, 'name' ) ); |
153 | if ( $projectCode ) { |
154 | # searched with a project name |
155 | $matchProject = $projectCode; |
156 | } else { |
157 | $this->getOutput()->addWikiMsg( 'wminc-searchwiki-noproject' ); |
158 | return; |
159 | } |
160 | } |
161 | |
162 | $results = []; |
163 | |
164 | $lcLanguageQuery = strtolower( $languageQuery ); |
165 | # The more important, the more below, because they override earlier codes |
166 | $validCodes = array_keys( $this->languageNameUtils->getLanguageNames( 'en', LanguageNameUtils::ALL ) ); |
167 | if ( in_array( $lcLanguageQuery, $validCodes ) ) { |
168 | $builtinCode = $this->languageFactory->getLanguage( $lcLanguageQuery )->getCode(); |
169 | $results[$builtinCode] = 'langcode'; # Match language code |
170 | } |
171 | $lcLanguageQuery = self::strip( $languageQuery ); |
172 | |
173 | $codeByEnglishName = array_search( |
174 | $lcLanguageQuery, array_map( [ self::class, 'strip' ], $this->mEnglishNames ) |
175 | ); |
176 | if ( $codeByEnglishName ) { |
177 | $results[$codeByEnglishName] = 'englishname'; # Match name in English |
178 | } |
179 | |
180 | $codeUserLang = array_search( |
181 | $lcLanguageQuery, array_map( [ self::class, 'strip' ], $this->mNamesUserLang ) |
182 | ); |
183 | if ( $codeUserLang ) { |
184 | $results[$codeUserLang] = 'userlangname'; # Match name in user language |
185 | } |
186 | |
187 | $codeByNativeName = array_search( |
188 | $lcLanguageQuery, array_map( [ self::class, 'strip' ], $this->mNativeNames ) |
189 | ); |
190 | if ( $codeByNativeName ) { |
191 | $results[$codeByNativeName] = 'nativename'; # Match native name |
192 | } |
193 | |
194 | if ( count( $results ) === 1 ) { |
195 | $this->gotoWiki( $matchProject, key( $results ) ); |
196 | } elseif ( count( $results ) < 1 ) { |
197 | $noresult = Html::element( 'p', [ 'class' => 'error' ], |
198 | $this->msg( 'wminc-searchwiki-noresults' )->text() ); |
199 | $this->getOutput()->addHTML( $noresult ); |
200 | return; |
201 | } elseif ( count( $results ) > 1 ) { |
202 | $this->showMultipleResults( $matchProject, $languageQuery, $results ); |
203 | } |
204 | } |
205 | |
206 | /** |
207 | * Improve search by increasing the chance of matches |
208 | * @param string $str |
209 | * @return string |
210 | */ |
211 | protected static function strip( $str ) { |
212 | $str = strtolower( trim( $str ) ); |
213 | $replace = [ ' ' => '', '-' => '' ]; |
214 | return str_replace( array_keys( $replace ), array_values( $replace ), $str ); |
215 | } |
216 | |
217 | /** |
218 | * Go directly to the wiki if it exists, else to the Incubator test wiki |
219 | * @param string $project project code |
220 | * @param string $lang Language code |
221 | */ |
222 | protected function goToWiki( $project, $lang ) { |
223 | $lang = $this->getRootCode( $lang ); |
224 | $dbarray = [ 'project' => $project, 'lang' => $lang, 'error' => null ]; |
225 | $status = WikimediaIncubator::getDBState( $dbarray ); |
226 | $infopageParams = [ |
227 | 'goto' => 'mainpage', |
228 | 'uselang' => $this->getRequest()->getVal( 'uselang' ) |
229 | ]; |
230 | $url = $status == 'existing' ? WikimediaIncubator::getSubdomain( |
231 | $this->getUser(), |
232 | $lang, |
233 | $project |
234 | ) : |
235 | Title::newFromText( 'W' . $project . '/' . $lang )->getFullURL( $infopageParams ); |
236 | $this->getOutput()->redirect( $url ); |
237 | } |
238 | |
239 | /** |
240 | * @param string $code |
241 | * @return string |
242 | */ |
243 | protected function getRootCode( $code ) { |
244 | # e.g. ks-arab -> ks |
245 | $stripLangTags = [ '-arab', '-latn', '-cyrl', '-deva', '-cans', '-grek' ]; |
246 | return str_replace( $stripLangTags, '', $code ); |
247 | } |
248 | |
249 | /** |
250 | * @param string $project |
251 | * @param string $languageQuery |
252 | * @param array $results |
253 | */ |
254 | protected function showMultipleResults( $project, $languageQuery, $results ) { |
255 | $this->getOutput()->addHTML( '<div id="wminc-searchwiki-results">' . |
256 | Xml::element( 'p', [], |
257 | $this->msg( 'wminc-searchwiki-multiplematches' )->text() ) . |
258 | '<ul>' |
259 | ); |
260 | $linkRenderer = $this->getLinkRenderer(); |
261 | foreach ( $results as $resultCode => $resultType ) { |
262 | $langName = $this->mNamesUserLang[$resultCode]; |
263 | $infopage = Title::newFromText( |
264 | WikimediaIncubator::displayPrefix( $project, $resultCode, true ) |
265 | ); |
266 | $linkInfoPage = $linkRenderer->makeKnownLink( $infopage, |
267 | $this->msg( 'wminc-searchwiki-gotoinfopage' )->text() |
268 | ); |
269 | # Give grep a chance to find the usages: |
270 | # wminc-infopage-title-p, wminc-infopage-title-b, wminc-infopage-title-t, |
271 | # wminc-infopage-title-q, wminc-infopage-title-n, wminc-infopage-title-s, |
272 | # wminc-infopage-title-v, wminc-infopage-title-y |
273 | $linkMainPage = $linkRenderer->makeKnownLink( $infopage, |
274 | $this->msg( 'wminc-infopage-title-' . $project, $langName )->text(), |
275 | [], [ 'goto' => 'mainpage' ] |
276 | ); |
277 | # Give grep a chance to find the usages: |
278 | # wminc-searchwiki-match-langcode, wminc-searchwiki-match-englishname, |
279 | # wminc-searchwiki-match-userlangname, wminc-searchwiki-match-nativename |
280 | $this->getOutput()->addHTML( '<li>' . |
281 | $this->msg( 'wminc-searchwiki-match-' . $resultType, |
282 | $languageQuery, $langName, $resultCode )->escaped() . ' ' . |
283 | $this->getLanguage()->getArrow() . ' ' . |
284 | $this->msg( 'wminc-searchwiki-goto', $linkMainPage, $linkInfoPage )->parse() . |
285 | '</li>' ); |
286 | } |
287 | $this->getOutput()->addHTML( '</ul></div>' ); |
288 | } |
289 | } |