MediaWiki  1.34.0
NamespaceInfo.php
Go to the documentation of this file.
1 <?php
26 
34 
41 
43  private $canonicalNamespaces = null;
44 
46  private $namespaceIndexes = false;
47 
49  private $validNamespaces = null;
50 
52  private $options;
53 
62  public static $canonicalNames = [
63  NS_MEDIA => 'Media',
64  NS_SPECIAL => 'Special',
65  NS_MAIN => '',
66  NS_TALK => 'Talk',
67  NS_USER => 'User',
68  NS_USER_TALK => 'User_talk',
69  NS_PROJECT => 'Project',
70  NS_PROJECT_TALK => 'Project_talk',
71  NS_FILE => 'File',
72  NS_FILE_TALK => 'File_talk',
73  NS_MEDIAWIKI => 'MediaWiki',
74  NS_MEDIAWIKI_TALK => 'MediaWiki_talk',
75  NS_TEMPLATE => 'Template',
76  NS_TEMPLATE_TALK => 'Template_talk',
77  NS_HELP => 'Help',
78  NS_HELP_TALK => 'Help_talk',
79  NS_CATEGORY => 'Category',
80  NS_CATEGORY_TALK => 'Category_talk',
81  ];
82 
89  public static $constructorOptions = [
90  'AllowImageMoving',
91  'CanonicalNamespaceNames',
92  'CapitalLinkOverrides',
93  'CapitalLinks',
94  'ContentNamespaces',
95  'ExtraNamespaces',
96  'ExtraSignatureNamespaces',
97  'NamespaceContentModels',
98  'NamespacesWithSubpages',
99  'NonincludableNamespaces',
100  ];
101 
105  public function __construct( ServiceOptions $options ) {
106  $options->assertRequiredOptions( self::$constructorOptions );
107  $this->options = $options;
108  }
109 
122  private function isMethodValidFor( $index, $method ) {
123  if ( $index < NS_MAIN ) {
124  throw new MWException( "$method does not make any sense for given namespace $index" );
125  }
126  return true;
127  }
128 
135  public function isMovable( $index ) {
136  $result = $index >= NS_MAIN &&
137  ( $index != NS_FILE || $this->options->get( 'AllowImageMoving' ) );
138 
142  Hooks::run( 'NamespaceIsMovable', [ $index, &$result ] );
143 
144  return $result;
145  }
146 
153  public function isSubject( $index ) {
154  return !$this->isTalk( $index );
155  }
156 
163  public function isTalk( $index ) {
164  return $index > NS_MAIN
165  && $index % 2;
166  }
167 
176  public function getTalk( $index ) {
177  $this->isMethodValidFor( $index, __METHOD__ );
178  return $this->isTalk( $index )
179  ? $index
180  : $index + 1;
181  }
182 
192  public function getTalkPage( LinkTarget $target ) : LinkTarget {
193  if ( $target->getText() === '' ) {
194  throw new MWException( 'Can\'t determine talk page associated with relative section link' );
195  }
196 
197  if ( $target->getInterwiki() !== '' ) {
198  throw new MWException( 'Can\'t determine talk page associated with interwiki link' );
199  }
200 
201  if ( $this->isTalk( $target->getNamespace() ) ) {
202  return $target;
203  }
204 
205  // NOTE: getTalk throws on bad namespaces!
206  return new TitleValue( $this->getTalk( $target->getNamespace() ), $target->getDBkey() );
207  }
208 
220  public function canHaveTalkPage( LinkTarget $target ) {
221  if ( $target->getText() === '' || $target->getInterwiki() !== '' ) {
222  return false;
223  }
224 
225  if ( $target->getNamespace() < NS_MAIN ) {
226  return false;
227  }
228 
229  return true;
230  }
231 
239  public function getSubject( $index ) {
240  # Handle special namespaces
241  if ( $index < NS_MAIN ) {
242  return $index;
243  }
244 
245  return $this->isTalk( $index )
246  ? $index - 1
247  : $index;
248  }
249 
254  public function getSubjectPage( LinkTarget $target ) : LinkTarget {
255  if ( $this->isSubject( $target->getNamespace() ) ) {
256  return $target;
257  }
258  return new TitleValue( $this->getSubject( $target->getNamespace() ), $target->getDBkey() );
259  }
260 
270  public function getAssociated( $index ) {
271  $this->isMethodValidFor( $index, __METHOD__ );
272 
273  if ( $this->isSubject( $index ) ) {
274  return $this->getTalk( $index );
275  }
276  return $this->getSubject( $index );
277  }
278 
285  public function getAssociatedPage( LinkTarget $target ) : LinkTarget {
286  if ( $target->getText() === '' ) {
287  throw new MWException( 'Can\'t determine talk page associated with relative section link' );
288  }
289 
290  if ( $target->getInterwiki() !== '' ) {
291  throw new MWException( 'Can\'t determine talk page associated with interwiki link' );
292  }
293 
294  return new TitleValue(
295  $this->getAssociated( $target->getNamespace() ), $target->getDBkey() );
296  }
297 
305  public function exists( $index ) {
306  $nslist = $this->getCanonicalNamespaces();
307  return isset( $nslist[$index] );
308  }
309 
323  public function equals( $ns1, $ns2 ) {
324  return $ns1 == $ns2;
325  }
326 
337  public function subjectEquals( $ns1, $ns2 ) {
338  return $this->getSubject( $ns1 ) == $this->getSubject( $ns2 );
339  }
340 
347  public function getCanonicalNamespaces() {
348  if ( $this->canonicalNamespaces === null ) {
349  $this->canonicalNamespaces =
350  [ NS_MAIN => '' ] + $this->options->get( 'CanonicalNamespaceNames' );
351  $this->canonicalNamespaces +=
352  ExtensionRegistry::getInstance()->getAttribute( 'ExtensionNamespaces' );
353  if ( is_array( $this->options->get( 'ExtraNamespaces' ) ) ) {
354  $this->canonicalNamespaces += $this->options->get( 'ExtraNamespaces' );
355  }
356  Hooks::run( 'CanonicalNamespaces', [ &$this->canonicalNamespaces ] );
357  }
359  }
360 
367  public function getCanonicalName( $index ) {
368  $nslist = $this->getCanonicalNamespaces();
369  return $nslist[$index] ?? false;
370  }
371 
379  public function getCanonicalIndex( $name ) {
380  if ( $this->namespaceIndexes === false ) {
381  $this->namespaceIndexes = [];
382  foreach ( $this->getCanonicalNamespaces() as $i => $text ) {
383  $this->namespaceIndexes[strtolower( $text )] = $i;
384  }
385  }
386  if ( array_key_exists( $name, $this->namespaceIndexes ) ) {
387  return $this->namespaceIndexes[$name];
388  } else {
389  return null;
390  }
391  }
392 
398  public function getValidNamespaces() {
399  if ( is_null( $this->validNamespaces ) ) {
400  $this->validNamespaces = [];
401  foreach ( array_keys( $this->getCanonicalNamespaces() ) as $ns ) {
402  if ( $ns >= 0 ) {
403  $this->validNamespaces[] = $ns;
404  }
405  }
406  // T109137: sort numerically
407  sort( $this->validNamespaces, SORT_NUMERIC );
408  }
409 
410  return $this->validNamespaces;
411  }
412 
413  /*
414 
421  public function hasTalkNamespace( $index ) {
422  return $index >= NS_MAIN;
423  }
424 
432  public function isContent( $index ) {
433  return $index == NS_MAIN || in_array( $index, $this->options->get( 'ContentNamespaces' ) );
434  }
435 
443  public function wantSignatures( $index ) {
444  return $this->isTalk( $index ) ||
445  in_array( $index, $this->options->get( 'ExtraSignatureNamespaces' ) );
446  }
447 
454  public function isWatchable( $index ) {
455  return $index >= NS_MAIN;
456  }
457 
464  public function hasSubpages( $index ) {
465  return !empty( $this->options->get( 'NamespacesWithSubpages' )[$index] );
466  }
467 
472  public function getContentNamespaces() {
473  $contentNamespaces = $this->options->get( 'ContentNamespaces' );
474  if ( !is_array( $contentNamespaces ) || $contentNamespaces === [] ) {
475  return [ NS_MAIN ];
476  } elseif ( !in_array( NS_MAIN, $contentNamespaces ) ) {
477  // always force NS_MAIN to be part of array (to match the algorithm used by isContent)
478  return array_merge( [ NS_MAIN ], $contentNamespaces );
479  } else {
480  return $contentNamespaces;
481  }
482  }
483 
490  public function getSubjectNamespaces() {
491  return array_filter(
492  $this->getValidNamespaces(),
493  [ $this, 'isSubject' ]
494  );
495  }
496 
503  public function getTalkNamespaces() {
504  return array_filter(
505  $this->getValidNamespaces(),
506  [ $this, 'isTalk' ]
507  );
508  }
509 
516  public function isCapitalized( $index ) {
517  // Turn NS_MEDIA into NS_FILE
518  $index = $index === NS_MEDIA ? NS_FILE : $index;
519 
520  // Make sure to get the subject of our namespace
521  $index = $this->getSubject( $index );
522 
523  // Some namespaces are special and should always be upper case
524  if ( in_array( $index, $this->alwaysCapitalizedNamespaces ) ) {
525  return true;
526  }
527  $overrides = $this->options->get( 'CapitalLinkOverrides' );
528  if ( isset( $overrides[$index] ) ) {
529  // CapitalLinkOverrides is explicitly set
530  return $overrides[$index];
531  }
532  // Default to the global setting
533  return $this->options->get( 'CapitalLinks' );
534  }
535 
543  public function hasGenderDistinction( $index ) {
544  return $index == NS_USER || $index == NS_USER_TALK;
545  }
546 
553  public function isNonincludable( $index ) {
554  $namespaces = $this->options->get( 'NonincludableNamespaces' );
555  return $namespaces && in_array( $index, $namespaces );
556  }
557 
568  public function getNamespaceContentModel( $index ) {
569  return $this->options->get( 'NamespaceContentModels' )[$index] ?? null;
570  }
571 
581  public function getRestrictionLevels( $index, User $user = null ) {
582  // PermissionManager is not injected because adding an explicit dependency
583  // breaks MW installer by adding a dependency chain on the database before
584  // it was set up. Also, the method is deprecated and will be soon removed.
585  return MediaWikiServices::getInstance()
586  ->getPermissionManager()
587  ->getNamespaceRestrictionLevels( $index, $user );
588  }
589 
599  public function getCategoryLinkType( $index ) {
600  $this->isMethodValidFor( $index, __METHOD__ );
601 
602  if ( $index == NS_CATEGORY ) {
603  return 'subcat';
604  } elseif ( $index == NS_FILE ) {
605  return 'file';
606  } else {
607  return 'page';
608  }
609  }
610 
618  public static function getCommonNamespaces() {
619  return array_keys( self::$canonicalNames );
620  }
621 }
MediaWiki\Linker\LinkTarget\getInterwiki
getInterwiki()
The interwiki component of this LinkTarget.
NamespaceInfo\__construct
__construct(ServiceOptions $options)
Definition: NamespaceInfo.php:105
MediaWiki\Linker\LinkTarget\getText
getText()
Returns the link in text form, without namespace prefix or fragment.
NamespaceInfo\isMovable
isMovable( $index)
Can pages in the given namespace be moved?
Definition: NamespaceInfo.php:135
NS_HELP
const NS_HELP
Definition: Defines.php:72
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:117
NS_TEMPLATE_TALK
const NS_TEMPLATE_TALK
Definition: Defines.php:71
NamespaceInfo\getAssociatedPage
getAssociatedPage(LinkTarget $target)
Definition: NamespaceInfo.php:285
NamespaceInfo\getValidNamespaces
getValidNamespaces()
Returns an array of the namespaces (by integer id) that exist on the wiki.
Definition: NamespaceInfo.php:398
NS_FILE
const NS_FILE
Definition: Defines.php:66
NamespaceInfo\getCanonicalNamespaces
getCanonicalNamespaces()
Returns array of all defined namespaces with their canonical (English) names.
Definition: NamespaceInfo.php:347
NS_TEMPLATE
const NS_TEMPLATE
Definition: Defines.php:70
NamespaceInfo\$options
ServiceOptions $options
Definition: NamespaceInfo.php:52
NamespaceInfo\subjectEquals
subjectEquals( $ns1, $ns2)
Returns whether the specified namespaces share the same subject.
Definition: NamespaceInfo.php:337
NamespaceInfo\isSubject
isSubject( $index)
Is the given namespace is a subject (non-talk) namespace?
Definition: NamespaceInfo.php:153
NamespaceInfo\$canonicalNamespaces
string[] null $canonicalNamespaces
Canonical namespaces cache.
Definition: NamespaceInfo.php:43
NamespaceInfo\$namespaceIndexes
array false $namespaceIndexes
Canonical namespaces index cache.
Definition: NamespaceInfo.php:46
NamespaceInfo\$canonicalNames
static array $canonicalNames
Definitions of the NS_ constants are in Defines.php.
Definition: NamespaceInfo.php:62
NS_MAIN
const NS_MAIN
Definition: Defines.php:60
ExtensionRegistry\getInstance
static getInstance()
Definition: ExtensionRegistry.php:106
NS_SPECIAL
const NS_SPECIAL
Definition: Defines.php:49
MediaWiki\Linker\LinkTarget\getNamespace
getNamespace()
Get the namespace index.
MWException
MediaWiki exception.
Definition: MWException.php:26
NS_PROJECT
const NS_PROJECT
Definition: Defines.php:64
MediaWiki\Config\ServiceOptions
A class for passing options to services.
Definition: ServiceOptions.php:25
NamespaceInfo\getSubject
getSubject( $index)
Get the subject namespace index for a given namespace Special namespaces (NS_MEDIA,...
Definition: NamespaceInfo.php:239
NamespaceInfo\getSubjectPage
getSubjectPage(LinkTarget $target)
Definition: NamespaceInfo.php:254
NamespaceInfo\canHaveTalkPage
canHaveTalkPage(LinkTarget $target)
Can the title have a corresponding talk page?
Definition: NamespaceInfo.php:220
NS_MEDIAWIKI_TALK
const NS_MEDIAWIKI_TALK
Definition: Defines.php:69
NamespaceInfo\getTalk
getTalk( $index)
Get the talk namespace index for a given namespace.
Definition: NamespaceInfo.php:176
NS_CATEGORY
const NS_CATEGORY
Definition: Defines.php:74
NamespaceInfo\$constructorOptions
static array $constructorOptions
TODO Make this const when HHVM support is dropped (T192166)
Definition: NamespaceInfo.php:89
NS_USER_TALK
const NS_USER_TALK
Definition: Defines.php:63
NS_MEDIA
const NS_MEDIA
Definition: Defines.php:48
NamespaceInfo\exists
exists( $index)
Returns whether the specified namespace exists.
Definition: NamespaceInfo.php:305
NamespaceInfo\$alwaysCapitalizedNamespaces
$alwaysCapitalizedNamespaces
These namespaces should always be first-letter capitalized, now and forevermore.
Definition: NamespaceInfo.php:40
MediaWiki\Linker\LinkTarget\getDBkey
getDBkey()
Get the main part with underscores.
NS_PROJECT_TALK
const NS_PROJECT_TALK
Definition: Defines.php:65
NamespaceInfo\getCanonicalName
getCanonicalName( $index)
Returns the canonical (English) name for a given index.
Definition: NamespaceInfo.php:367
NamespaceInfo\isTalk
isTalk( $index)
Is the given namespace a talk namespace?
Definition: NamespaceInfo.php:163
NamespaceInfo\equals
equals( $ns1, $ns2)
Returns whether the specified namespaces are the same namespace.
Definition: NamespaceInfo.php:323
NamespaceInfo\getCanonicalIndex
getCanonicalIndex( $name)
Returns the index for a given canonical name, or NULL The input must be converted to lower case first...
Definition: NamespaceInfo.php:379
NS_HELP_TALK
const NS_HELP_TALK
Definition: Defines.php:73
NS_USER
const NS_USER
Definition: Defines.php:62
NS_TALK
const NS_TALK
Definition: Defines.php:61
NamespaceInfo\getTalkPage
getTalkPage(LinkTarget $target)
Get a LinkTarget referring to the talk page of $target.
Definition: NamespaceInfo.php:192
NamespaceInfo
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Definition: NamespaceInfo.php:33
NS_MEDIAWIKI
const NS_MEDIAWIKI
Definition: Defines.php:68
NamespaceInfo\$validNamespaces
int[] null $validNamespaces
Valid namespaces cache.
Definition: NamespaceInfo.php:49
MediaWiki\Linker\LinkTarget
Definition: LinkTarget.php:26
NS_FILE_TALK
const NS_FILE_TALK
Definition: Defines.php:67
NS_CATEGORY_TALK
const NS_CATEGORY_TALK
Definition: Defines.php:75
NamespaceInfo\isMethodValidFor
isMethodValidFor( $index, $method)
Throw an exception when trying to get the subject or talk page for a given namespace where it does no...
Definition: NamespaceInfo.php:122
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200
NamespaceInfo\getAssociated
getAssociated( $index)
Get the associated namespace.
Definition: NamespaceInfo.php:270
MediaWiki\Config\ServiceOptions\assertRequiredOptions
assertRequiredOptions(array $expectedKeys)
Assert that the list of options provided in this instance exactly match $expectedKeys,...
Definition: ServiceOptions.php:62
TitleValue
Represents a page (or page fragment) title within MediaWiki.
Definition: TitleValue.php:36