Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
91.34% |
116 / 127 |
|
94.12% |
32 / 34 |
CRAP | |
0.00% |
0 / 1 |
NamespaceInfo | |
92.06% |
116 / 126 |
|
94.12% |
32 / 34 |
75.66 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
isMethodValidFor | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
makeValidNamespace | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
30 | |||
isMovable | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
isSubject | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isTalk | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
getTalk | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
getTalkPage | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
4 | |||
canHaveTalkPage | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
3 | |||
getSubject | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
getSubjectPage | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
getAssociated | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
getAssociatedPage | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
exists | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
equals | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
subjectEquals | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getCanonicalNamespaces | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
3 | |||
getCanonicalName | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getCanonicalIndex | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
4 | |||
getValidNamespaces | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
4 | |||
hasTalkNamespace | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isContent | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
wantSignatures | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
isWatchable | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
hasSubpages | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getContentNamespaces | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
4 | |||
getSubjectNamespaces | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
getTalkNamespaces | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
isCapitalized | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
4 | |||
hasGenderDistinction | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
isNonincludable | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
getNamespaceContentModel | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getCategoryLinkType | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
getCommonNamespaces | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * Provide things related to namespaces. |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License along |
16 | * with this program; if not, write to the Free Software Foundation, Inc., |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | * http://www.gnu.org/copyleft/gpl.html |
19 | * |
20 | * @file |
21 | */ |
22 | |
23 | namespace MediaWiki\Title; |
24 | |
25 | use InvalidArgumentException; |
26 | use MediaWiki\Config\ServiceOptions; |
27 | use MediaWiki\HookContainer\HookContainer; |
28 | use MediaWiki\HookContainer\HookRunner; |
29 | use MediaWiki\Linker\LinkTarget; |
30 | use MediaWiki\MainConfigNames; |
31 | use MWException; |
32 | |
33 | /** |
34 | * This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of |
35 | * them based on index. The textual names of the namespaces are handled by Language.php. |
36 | * |
37 | * @since 1.34 |
38 | */ |
39 | class NamespaceInfo { |
40 | |
41 | /** |
42 | * These namespaces should always be first-letter capitalized, now and |
43 | * forevermore. Historically, they could've probably been lowercased too, |
44 | * but some things are just too ingrained now. :) |
45 | */ |
46 | private $alwaysCapitalizedNamespaces = [ NS_SPECIAL, NS_USER, NS_MEDIAWIKI ]; |
47 | |
48 | /** @var string[]|null Canonical namespaces cache */ |
49 | private $canonicalNamespaces = null; |
50 | |
51 | /** @var array|false Canonical namespaces index cache */ |
52 | private $namespaceIndexes = false; |
53 | |
54 | /** @var int[]|null Valid namespaces cache */ |
55 | private $validNamespaces = null; |
56 | |
57 | /** @var ServiceOptions */ |
58 | private $options; |
59 | |
60 | /** @var HookRunner */ |
61 | private $hookRunner; |
62 | |
63 | private array $extensionNamespaces; |
64 | |
65 | private array $extensionImmovableNamespaces; |
66 | |
67 | /** |
68 | * Definitions of the NS_ constants are in Defines.php |
69 | * |
70 | * @internal |
71 | */ |
72 | public const CANONICAL_NAMES = [ |
73 | NS_MEDIA => 'Media', |
74 | NS_SPECIAL => 'Special', |
75 | NS_MAIN => '', |
76 | NS_TALK => 'Talk', |
77 | NS_USER => 'User', |
78 | NS_USER_TALK => 'User_talk', |
79 | NS_PROJECT => 'Project', |
80 | NS_PROJECT_TALK => 'Project_talk', |
81 | NS_FILE => 'File', |
82 | NS_FILE_TALK => 'File_talk', |
83 | NS_MEDIAWIKI => 'MediaWiki', |
84 | NS_MEDIAWIKI_TALK => 'MediaWiki_talk', |
85 | NS_TEMPLATE => 'Template', |
86 | NS_TEMPLATE_TALK => 'Template_talk', |
87 | NS_HELP => 'Help', |
88 | NS_HELP_TALK => 'Help_talk', |
89 | NS_CATEGORY => 'Category', |
90 | NS_CATEGORY_TALK => 'Category_talk', |
91 | ]; |
92 | |
93 | /** |
94 | * @internal For use by ServiceWiring |
95 | */ |
96 | public const CONSTRUCTOR_OPTIONS = [ |
97 | MainConfigNames::CanonicalNamespaceNames, |
98 | MainConfigNames::CapitalLinkOverrides, |
99 | MainConfigNames::CapitalLinks, |
100 | MainConfigNames::ContentNamespaces, |
101 | MainConfigNames::ExtraNamespaces, |
102 | MainConfigNames::ExtraSignatureNamespaces, |
103 | MainConfigNames::NamespaceContentModels, |
104 | MainConfigNames::NamespacesWithSubpages, |
105 | MainConfigNames::NonincludableNamespaces, |
106 | ]; |
107 | |
108 | /** |
109 | * @param ServiceOptions $options |
110 | * @param HookContainer $hookContainer |
111 | * @param array $extensionNamespaces |
112 | * @param array $extensionImmovableNamespaces |
113 | */ |
114 | public function __construct( |
115 | ServiceOptions $options, |
116 | HookContainer $hookContainer, |
117 | array $extensionNamespaces, |
118 | array $extensionImmovableNamespaces |
119 | ) { |
120 | $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS ); |
121 | $this->options = $options; |
122 | $this->hookRunner = new HookRunner( $hookContainer ); |
123 | $this->extensionNamespaces = $extensionNamespaces; |
124 | $this->extensionImmovableNamespaces = $extensionImmovableNamespaces; |
125 | } |
126 | |
127 | /** |
128 | * Throw an exception when trying to get the subject or talk page |
129 | * for a given namespace where it does not make sense. |
130 | * Special namespaces are defined in includes/Defines.php and have |
131 | * a value below 0 (ex: NS_SPECIAL = -1 , NS_MEDIA = -2) |
132 | * |
133 | * @param int $index |
134 | * @param string $method |
135 | * |
136 | * @throws MWException |
137 | * @return bool |
138 | */ |
139 | private function isMethodValidFor( $index, $method ) { |
140 | if ( $index < NS_MAIN ) { |
141 | throw new MWException( "$method does not make any sense for given namespace $index" ); |
142 | } |
143 | return true; |
144 | } |
145 | |
146 | /** |
147 | * Throw if given index isn't an integer or integer-like string and so can't be a valid namespace. |
148 | * |
149 | * @param int|string $index |
150 | * @param string $method |
151 | * |
152 | * @throws InvalidArgumentException |
153 | * @return int Cleaned up namespace index |
154 | */ |
155 | private function makeValidNamespace( $index, $method ) { |
156 | if ( !( |
157 | is_int( $index ) |
158 | // Namespace index numbers as strings |
159 | || ctype_digit( $index ) |
160 | // Negative numbers as strings |
161 | || ( $index[0] === '-' && ctype_digit( substr( $index, 1 ) ) ) |
162 | ) ) { |
163 | throw new InvalidArgumentException( |
164 | "$method called with non-integer (" . gettype( $index ) . ") namespace '$index'" |
165 | ); |
166 | } |
167 | |
168 | return intval( $index ); |
169 | } |
170 | |
171 | /** |
172 | * Can pages in the given namespace be moved? |
173 | * |
174 | * @param int $index Namespace index |
175 | * @return bool |
176 | */ |
177 | public function isMovable( $index ) { |
178 | $result = $index >= NS_MAIN && !in_array( $index, $this->extensionImmovableNamespaces ); |
179 | |
180 | /** |
181 | * @since 1.20 |
182 | */ |
183 | $this->hookRunner->onNamespaceIsMovable( $index, $result ); |
184 | |
185 | return $result; |
186 | } |
187 | |
188 | /** |
189 | * Is the given namespace is a subject (non-talk) namespace? |
190 | * |
191 | * @param int $index Namespace index |
192 | * @return bool |
193 | */ |
194 | public function isSubject( $index ) { |
195 | return !$this->isTalk( $index ); |
196 | } |
197 | |
198 | /** |
199 | * Is the given namespace a talk namespace? |
200 | * |
201 | * @param int $index Namespace index |
202 | * @return bool |
203 | */ |
204 | public function isTalk( $index ) { |
205 | $index = $this->makeValidNamespace( $index, __METHOD__ ); |
206 | |
207 | return $index > NS_MAIN |
208 | && $index % 2 === 1; |
209 | } |
210 | |
211 | /** |
212 | * Get the talk namespace index for a given namespace |
213 | * |
214 | * @param int $index Namespace index |
215 | * @return int |
216 | * @throws MWException if the given namespace doesn't have an associated talk namespace |
217 | * (e.g. NS_SPECIAL). |
218 | */ |
219 | public function getTalk( $index ) { |
220 | $index = $this->makeValidNamespace( $index, __METHOD__ ); |
221 | |
222 | $this->isMethodValidFor( $index, __METHOD__ ); |
223 | return $this->isTalk( $index ) |
224 | ? $index |
225 | : $index + 1; |
226 | } |
227 | |
228 | /** |
229 | * Get a LinkTarget referring to the talk page of $target. |
230 | * |
231 | * @see canHaveTalkPage |
232 | * @param LinkTarget $target |
233 | * @return LinkTarget Talk page for $target |
234 | * @throws MWException if $target doesn't have talk pages, e.g. because it's in NS_SPECIAL, |
235 | * because it's a relative section-only link, or it's an interwiki link. |
236 | */ |
237 | public function getTalkPage( LinkTarget $target ): LinkTarget { |
238 | if ( $target->getText() === '' ) { |
239 | throw new MWException( 'Can\'t determine talk page associated with relative section link' ); |
240 | } |
241 | |
242 | if ( $target->getInterwiki() !== '' ) { |
243 | throw new MWException( 'Can\'t determine talk page associated with interwiki link' ); |
244 | } |
245 | |
246 | if ( $this->isTalk( $target->getNamespace() ) ) { |
247 | return $target; |
248 | } |
249 | |
250 | // NOTE: getTalk throws on bad namespaces! |
251 | return new TitleValue( $this->getTalk( $target->getNamespace() ), $target->getDBkey() ); |
252 | } |
253 | |
254 | /** |
255 | * Can the title have a corresponding talk page? |
256 | * |
257 | * False for relative section-only links (with getText() === ''), |
258 | * interwiki links (with getInterwiki() !== ''), and pages in NS_SPECIAL. |
259 | * |
260 | * @see getTalkPage |
261 | * |
262 | * @param LinkTarget $target |
263 | * @return bool True if this title either is a talk page or can have a talk page associated. |
264 | */ |
265 | public function canHaveTalkPage( LinkTarget $target ) { |
266 | return $target->getNamespace() >= NS_MAIN && |
267 | !$target->isExternal() && |
268 | $target->getText() !== ''; |
269 | } |
270 | |
271 | /** |
272 | * Get the subject namespace index for a given namespace |
273 | * Special namespaces (NS_MEDIA, NS_SPECIAL) are always the subject. |
274 | * |
275 | * @param int $index Namespace index |
276 | * @return int |
277 | */ |
278 | public function getSubject( $index ) { |
279 | $index = $this->makeValidNamespace( $index, __METHOD__ ); |
280 | |
281 | # Handle special namespaces |
282 | if ( $index < NS_MAIN ) { |
283 | return $index; |
284 | } |
285 | |
286 | return $this->isTalk( $index ) |
287 | ? $index - 1 |
288 | : $index; |
289 | } |
290 | |
291 | /** |
292 | * @param LinkTarget $target |
293 | * @return LinkTarget Subject page for $target |
294 | */ |
295 | public function getSubjectPage( LinkTarget $target ): LinkTarget { |
296 | if ( $this->isSubject( $target->getNamespace() ) ) { |
297 | return $target; |
298 | } |
299 | return new TitleValue( $this->getSubject( $target->getNamespace() ), $target->getDBkey() ); |
300 | } |
301 | |
302 | /** |
303 | * Get the associated namespace. |
304 | * For talk namespaces, returns the subject (non-talk) namespace |
305 | * For subject (non-talk) namespaces, returns the talk namespace |
306 | * |
307 | * @param int $index Namespace index |
308 | * @return int |
309 | * @throws MWException if called on a namespace that has no talk pages (e.g., NS_SPECIAL) |
310 | */ |
311 | public function getAssociated( $index ) { |
312 | $this->isMethodValidFor( $index, __METHOD__ ); |
313 | |
314 | if ( $this->isSubject( $index ) ) { |
315 | return $this->getTalk( $index ); |
316 | } |
317 | return $this->getSubject( $index ); |
318 | } |
319 | |
320 | /** |
321 | * @param LinkTarget $target |
322 | * @return LinkTarget Talk page for $target if it's a subject page, subject page if it's a talk |
323 | * page |
324 | * @throws MWException if $target's namespace doesn't have talk pages (e.g., NS_SPECIAL) |
325 | */ |
326 | public function getAssociatedPage( LinkTarget $target ): LinkTarget { |
327 | if ( $target->getText() === '' ) { |
328 | throw new MWException( 'Can\'t determine talk page associated with relative section link' ); |
329 | } |
330 | |
331 | if ( $target->getInterwiki() !== '' ) { |
332 | throw new MWException( 'Can\'t determine talk page associated with interwiki link' ); |
333 | } |
334 | |
335 | return new TitleValue( |
336 | $this->getAssociated( $target->getNamespace() ), $target->getDBkey() ); |
337 | } |
338 | |
339 | /** |
340 | * Returns whether the specified namespace exists |
341 | * |
342 | * @param int $index |
343 | * |
344 | * @return bool |
345 | */ |
346 | public function exists( $index ) { |
347 | $nslist = $this->getCanonicalNamespaces(); |
348 | return isset( $nslist[$index] ); |
349 | } |
350 | |
351 | /** |
352 | * Returns whether the specified namespaces are the same namespace |
353 | * |
354 | * @note It's possible that in the future we may start using something |
355 | * other than just namespace indexes. Under that circumstance making use |
356 | * of this function rather than directly doing comparison will make |
357 | * sure that code will not potentially break. |
358 | * |
359 | * @param int $ns1 The first namespace index |
360 | * @param int $ns2 The second namespace index |
361 | * |
362 | * @return bool |
363 | */ |
364 | public function equals( $ns1, $ns2 ) { |
365 | return $ns1 == $ns2; |
366 | } |
367 | |
368 | /** |
369 | * Returns whether the specified namespaces share the same subject. |
370 | * eg: NS_USER and NS_USER wil return true, as well |
371 | * NS_USER and NS_USER_TALK will return true. |
372 | * |
373 | * @param int $ns1 The first namespace index |
374 | * @param int $ns2 The second namespace index |
375 | * |
376 | * @return bool |
377 | */ |
378 | public function subjectEquals( $ns1, $ns2 ) { |
379 | return $this->getSubject( $ns1 ) == $this->getSubject( $ns2 ); |
380 | } |
381 | |
382 | /** |
383 | * Returns array of all defined namespaces with their canonical |
384 | * (English) names. |
385 | * |
386 | * @return string[] |
387 | */ |
388 | public function getCanonicalNamespaces() { |
389 | if ( $this->canonicalNamespaces === null ) { |
390 | $this->canonicalNamespaces = |
391 | [ NS_MAIN => '' ] + $this->options->get( MainConfigNames::CanonicalNamespaceNames ); |
392 | $this->canonicalNamespaces += $this->extensionNamespaces; |
393 | if ( is_array( $this->options->get( MainConfigNames::ExtraNamespaces ) ) ) { |
394 | $this->canonicalNamespaces += $this->options->get( MainConfigNames::ExtraNamespaces ); |
395 | } |
396 | $this->hookRunner->onCanonicalNamespaces( $this->canonicalNamespaces ); |
397 | } |
398 | return $this->canonicalNamespaces; |
399 | } |
400 | |
401 | /** |
402 | * Returns the canonical (English) name for a given index |
403 | * |
404 | * @param int $index Namespace index |
405 | * @return string|false If no canonical definition. |
406 | */ |
407 | public function getCanonicalName( $index ) { |
408 | $nslist = $this->getCanonicalNamespaces(); |
409 | return $nslist[$index] ?? false; |
410 | } |
411 | |
412 | /** |
413 | * Returns the index for a given canonical name, or NULL |
414 | * The input *must* be converted to lower case first |
415 | * |
416 | * @param string $name Namespace name |
417 | * @return int|null |
418 | */ |
419 | public function getCanonicalIndex( $name ) { |
420 | if ( $this->namespaceIndexes === false ) { |
421 | $this->namespaceIndexes = []; |
422 | foreach ( $this->getCanonicalNamespaces() as $i => $text ) { |
423 | $this->namespaceIndexes[strtolower( $text )] = $i; |
424 | } |
425 | } |
426 | if ( array_key_exists( $name, $this->namespaceIndexes ) ) { |
427 | return $this->namespaceIndexes[$name]; |
428 | } else { |
429 | return null; |
430 | } |
431 | } |
432 | |
433 | /** |
434 | * Returns an array of the namespaces (by integer id) that exist on the wiki. Used primarily by |
435 | * the API in help documentation. The array is sorted numerically and omits negative namespaces. |
436 | * @return array |
437 | */ |
438 | public function getValidNamespaces() { |
439 | if ( $this->validNamespaces === null ) { |
440 | $this->validNamespaces = []; |
441 | foreach ( $this->getCanonicalNamespaces() as $ns => $_ ) { |
442 | if ( $ns >= 0 ) { |
443 | $this->validNamespaces[] = $ns; |
444 | } |
445 | } |
446 | // T109137: sort numerically |
447 | sort( $this->validNamespaces, SORT_NUMERIC ); |
448 | } |
449 | |
450 | return $this->validNamespaces; |
451 | } |
452 | |
453 | /** |
454 | * Does this namespace ever have a talk namespace? |
455 | * |
456 | * @param int $index Namespace ID |
457 | * @return bool True if this namespace either is or has a corresponding talk namespace. |
458 | */ |
459 | public function hasTalkNamespace( $index ) { |
460 | return $index >= NS_MAIN; |
461 | } |
462 | |
463 | /** |
464 | * Does this namespace contain content, for the purposes of calculating |
465 | * statistics, etc? |
466 | * |
467 | * @param int $index Index to check |
468 | * @return bool |
469 | */ |
470 | public function isContent( $index ) { |
471 | return $index == NS_MAIN || |
472 | in_array( $index, $this->options->get( MainConfigNames::ContentNamespaces ) ); |
473 | } |
474 | |
475 | /** |
476 | * Might pages in this namespace require the use of the Signature button on |
477 | * the edit toolbar? |
478 | * |
479 | * @param int $index Index to check |
480 | * @return bool |
481 | */ |
482 | public function wantSignatures( $index ) { |
483 | return $this->isTalk( $index ) || |
484 | in_array( $index, $this->options->get( MainConfigNames::ExtraSignatureNamespaces ) ); |
485 | } |
486 | |
487 | /** |
488 | * Can pages in a namespace be watched? |
489 | * |
490 | * @param int $index |
491 | * @return bool |
492 | */ |
493 | public function isWatchable( $index ) { |
494 | return $index >= NS_MAIN; |
495 | } |
496 | |
497 | /** |
498 | * Does the namespace allow subpages? Note that this refers to structured |
499 | * handling of subpages, and does not include SpecialPage subpage parameters. |
500 | * |
501 | * @param int $index Index to check |
502 | * @return bool |
503 | */ |
504 | public function hasSubpages( $index ) { |
505 | return !empty( $this->options->get( MainConfigNames::NamespacesWithSubpages )[$index] ); |
506 | } |
507 | |
508 | /** |
509 | * Get a list of all namespace indices which are considered to contain content |
510 | * @return int[] Array of namespace indices |
511 | */ |
512 | public function getContentNamespaces() { |
513 | $contentNamespaces = $this->options->get( MainConfigNames::ContentNamespaces ); |
514 | if ( !is_array( $contentNamespaces ) || $contentNamespaces === [] ) { |
515 | return [ NS_MAIN ]; |
516 | } elseif ( !in_array( NS_MAIN, $contentNamespaces ) ) { |
517 | // always force NS_MAIN to be part of array (to match the algorithm used by isContent) |
518 | return array_merge( [ NS_MAIN ], $contentNamespaces ); |
519 | } else { |
520 | return $contentNamespaces; |
521 | } |
522 | } |
523 | |
524 | /** |
525 | * List all namespace indices which are considered subject, aka not a talk |
526 | * or special namespace. See also NamespaceInfo::isSubject |
527 | * |
528 | * @return int[] Array of namespace indices |
529 | */ |
530 | public function getSubjectNamespaces() { |
531 | return array_filter( |
532 | $this->getValidNamespaces(), |
533 | [ $this, 'isSubject' ] |
534 | ); |
535 | } |
536 | |
537 | /** |
538 | * List all namespace indices which are considered talks, aka not a subject |
539 | * or special namespace. See also NamespaceInfo::isTalk |
540 | * |
541 | * @return int[] Array of namespace indices |
542 | */ |
543 | public function getTalkNamespaces() { |
544 | return array_filter( |
545 | $this->getValidNamespaces(), |
546 | [ $this, 'isTalk' ] |
547 | ); |
548 | } |
549 | |
550 | /** |
551 | * Is the namespace first-letter capitalized? |
552 | * |
553 | * @param int $index Index to check |
554 | * @return bool |
555 | */ |
556 | public function isCapitalized( $index ) { |
557 | // Turn NS_MEDIA into NS_FILE |
558 | $index = $index === NS_MEDIA ? NS_FILE : $index; |
559 | |
560 | // Make sure to get the subject of our namespace |
561 | $index = $this->getSubject( $index ); |
562 | |
563 | // Some namespaces are special and should always be upper case |
564 | if ( in_array( $index, $this->alwaysCapitalizedNamespaces ) ) { |
565 | return true; |
566 | } |
567 | $overrides = $this->options->get( MainConfigNames::CapitalLinkOverrides ); |
568 | if ( isset( $overrides[$index] ) ) { |
569 | // CapitalLinkOverrides is explicitly set |
570 | return $overrides[$index]; |
571 | } |
572 | // Default to the global setting |
573 | return $this->options->get( MainConfigNames::CapitalLinks ); |
574 | } |
575 | |
576 | /** |
577 | * Does the namespace (potentially) have different aliases for different |
578 | * genders. Not all languages make a distinction here. |
579 | * |
580 | * @param int $index Index to check |
581 | * @return bool |
582 | */ |
583 | public function hasGenderDistinction( $index ) { |
584 | return $index == NS_USER || $index == NS_USER_TALK; |
585 | } |
586 | |
587 | /** |
588 | * It is not possible to use pages from this namespace as template? |
589 | * |
590 | * @param int $index Index to check |
591 | * @return bool |
592 | */ |
593 | public function isNonincludable( $index ) { |
594 | $namespaces = $this->options->get( MainConfigNames::NonincludableNamespaces ); |
595 | return $namespaces && in_array( $index, $namespaces ); |
596 | } |
597 | |
598 | /** |
599 | * Get the default content model for a namespace |
600 | * This does not mean that all pages in that namespace have the model |
601 | * |
602 | * @note To determine the default model for a new page's main slot, or any slot in general, |
603 | * use SlotRoleHandler::getDefaultModel() together with SlotRoleRegistry::getRoleHandler(). |
604 | * |
605 | * @param int $index Index to check |
606 | * @return null|string Default model name for the given namespace, if set |
607 | */ |
608 | public function getNamespaceContentModel( $index ) { |
609 | return $this->options->get( MainConfigNames::NamespaceContentModels )[$index] ?? null; |
610 | } |
611 | |
612 | /** |
613 | * Returns the link type to be used for categories. |
614 | * |
615 | * This determines which section of a category page titles |
616 | * in the namespace will appear within. |
617 | * |
618 | * @param int $index Namespace index |
619 | * @return string One of 'subcat', 'file', 'page' |
620 | */ |
621 | public function getCategoryLinkType( $index ) { |
622 | $this->isMethodValidFor( $index, __METHOD__ ); |
623 | |
624 | if ( $index == NS_CATEGORY ) { |
625 | return 'subcat'; |
626 | } elseif ( $index == NS_FILE ) { |
627 | return 'file'; |
628 | } else { |
629 | return 'page'; |
630 | } |
631 | } |
632 | |
633 | /** |
634 | * Retrieve the indexes for the namespaces defined by core. |
635 | * |
636 | * @since 1.34 |
637 | * |
638 | * @return int[] |
639 | */ |
640 | public static function getCommonNamespaces() { |
641 | return array_keys( self::CANONICAL_NAMES ); |
642 | } |
643 | } |
644 | |
645 | /** @deprecated class alias since 1.41 */ |
646 | class_alias( NamespaceInfo::class, 'NamespaceInfo' ); |