/includes/Namespace.php

https://github.com/daevid/MWFork · PHP · 312 lines · 133 code · 28 blank · 151 comment · 30 complexity · 3466a557fe09f233651fd740aa1a56cc MD5 · raw file

  1. <?php
  2. /**
  3. * Provide things related to namespaces
  4. * @file
  5. */
  6. /**
  7. * This is a utility class with only static functions
  8. * for dealing with namespaces that encodes all the
  9. * "magic" behaviors of them based on index. The textual
  10. * names of the namespaces are handled by Language.php.
  11. *
  12. * These are synonyms for the names given in the language file
  13. * Users and translators should not change them
  14. *
  15. */
  16. class MWNamespace {
  17. /**
  18. * These namespaces should always be first-letter capitalized, now and
  19. * forevermore. Historically, they could've probably been lowercased too,
  20. * but some things are just too ingrained now. :)
  21. */
  22. private static $alwaysCapitalizedNamespaces = array( NS_SPECIAL, NS_USER, NS_MEDIAWIKI );
  23. /**
  24. * Throw an exception when trying to get the subject or talk page
  25. * for a given namespace where it does not make sense.
  26. * Special namespaces are defined in includes/define.php and have
  27. * a value below 0 (ex: NS_SPECIAL = -1 , NS_MEDIA = -2)
  28. *
  29. * @param $index
  30. * @param $method
  31. *
  32. * @return true
  33. */
  34. private static function isMethodValidFor( $index, $method ) {
  35. if( $index < NS_MAIN ) {
  36. throw new MWException( "$method does not make any sense for given namespace $index" );
  37. }
  38. return true;
  39. }
  40. /**
  41. * Can pages in the given namespace be moved?
  42. *
  43. * @param $index Int: namespace index
  44. * @return bool
  45. */
  46. public static function isMovable( $index ) {
  47. global $wgAllowImageMoving;
  48. return !( $index < NS_MAIN || ($index == NS_FILE && !$wgAllowImageMoving) || $index == NS_CATEGORY );
  49. }
  50. /**
  51. * Is the given namespace is a subject (non-talk) namespace?
  52. *
  53. * @param $index Int: namespace index
  54. * @return bool
  55. */
  56. public static function isMain( $index ) {
  57. return !self::isTalk( $index );
  58. }
  59. /**
  60. * Is the given namespace a talk namespace?
  61. *
  62. * @param $index Int: namespace index
  63. * @return bool
  64. */
  65. public static function isTalk( $index ) {
  66. return $index > NS_MAIN
  67. && $index % 2;
  68. }
  69. /**
  70. * Get the talk namespace index for a given namespace
  71. *
  72. * @param $index Int: namespace index
  73. * @return int
  74. */
  75. public static function getTalk( $index ) {
  76. self::isMethodValidFor( $index, __METHOD__ );
  77. return self::isTalk( $index )
  78. ? $index
  79. : $index + 1;
  80. }
  81. /**
  82. * Get the subject namespace index for a given namespace
  83. * Special namespaces (NS_MEDIA, NS_SPECIAL) are always the subject.
  84. *
  85. * @param $index Int: Namespace index
  86. * @return int
  87. */
  88. public static function getSubject( $index ) {
  89. # Handle special namespaces
  90. if( $index < NS_MAIN ) {
  91. return $index;
  92. }
  93. return self::isTalk( $index )
  94. ? $index - 1
  95. : $index;
  96. }
  97. /**
  98. * Get the associated namespace.
  99. * For talk namespaces, returns the subject (non-talk) namespace
  100. * For subject (non-talk) namespaces, returns the talk namespace
  101. *
  102. * @param $index Int: namespace index
  103. * @return int or null if no associated namespace could be found
  104. */
  105. public static function getAssociated( $index ) {
  106. self::isMethodValidFor( $index, __METHOD__ );
  107. if( self::isMain( $index ) ) {
  108. return self::getTalk( $index );
  109. } elseif( self::isTalk( $index ) ) {
  110. return self::getSubject( $index );
  111. } else {
  112. return null;
  113. }
  114. }
  115. /**
  116. * Returns whether the specified namespace exists
  117. *
  118. * @param $index
  119. *
  120. * @return bool
  121. */
  122. public static function exists( $index ) {
  123. $nslist = self::getCanonicalNamespaces();
  124. return isset( $nslist[$index] );
  125. }
  126. /**
  127. * Returns array of all defined namespaces with their canonical
  128. * (English) names.
  129. *
  130. * @return \array
  131. * @since 1.17
  132. */
  133. public static function getCanonicalNamespaces() {
  134. static $namespaces = null;
  135. if ( $namespaces === null ) {
  136. global $wgExtraNamespaces, $wgCanonicalNamespaceNames;
  137. $namespaces = array( NS_MAIN => '' ) + $wgCanonicalNamespaceNames;
  138. if ( is_array( $wgExtraNamespaces ) ) {
  139. $namespaces += $wgExtraNamespaces;
  140. }
  141. wfRunHooks( 'CanonicalNamespaces', array( &$namespaces ) );
  142. }
  143. return $namespaces;
  144. }
  145. /**
  146. * Returns the canonical (English) name for a given index
  147. *
  148. * @param $index Int: namespace index
  149. * @return string or false if no canonical definition.
  150. */
  151. public static function getCanonicalName( $index ) {
  152. $nslist = self::getCanonicalNamespaces();
  153. if( isset( $nslist[$index] ) ) {
  154. return $nslist[$index];
  155. } else {
  156. return false;
  157. }
  158. }
  159. /**
  160. * Returns the index for a given canonical name, or NULL
  161. * The input *must* be converted to lower case first
  162. *
  163. * @param $name String: namespace name
  164. * @return int
  165. */
  166. public static function getCanonicalIndex( $name ) {
  167. static $xNamespaces = false;
  168. if ( $xNamespaces === false ) {
  169. $xNamespaces = array();
  170. foreach ( self::getCanonicalNamespaces() as $i => $text ) {
  171. $xNamespaces[strtolower($text)] = $i;
  172. }
  173. }
  174. if ( array_key_exists( $name, $xNamespaces ) ) {
  175. return $xNamespaces[$name];
  176. } else {
  177. return null;
  178. }
  179. }
  180. /**
  181. * Returns an array of the namespaces (by integer id) that exist on the
  182. * wiki. Used primarily by the api in help documentation.
  183. * @return array
  184. */
  185. public static function getValidNamespaces() {
  186. static $mValidNamespaces = null;
  187. if ( is_null( $mValidNamespaces ) ) {
  188. foreach ( array_keys( self::getCanonicalNamespaces() ) as $ns ) {
  189. if ( $ns >= 0 ) {
  190. $mValidNamespaces[] = $ns;
  191. }
  192. }
  193. }
  194. return $mValidNamespaces;
  195. }
  196. /**
  197. * Can this namespace ever have a talk namespace?
  198. *
  199. * @param $index Int: namespace index
  200. * @return bool
  201. */
  202. public static function canTalk( $index ) {
  203. return $index >= NS_MAIN;
  204. }
  205. /**
  206. * Does this namespace contain content, for the purposes of calculating
  207. * statistics, etc?
  208. *
  209. * @param $index Int: index to check
  210. * @return bool
  211. */
  212. public static function isContent( $index ) {
  213. global $wgContentNamespaces;
  214. return $index == NS_MAIN || in_array( $index, $wgContentNamespaces );
  215. }
  216. /**
  217. * Can pages in a namespace be watched?
  218. *
  219. * @param $index Int
  220. * @return bool
  221. */
  222. public static function isWatchable( $index ) {
  223. return $index >= NS_MAIN;
  224. }
  225. /**
  226. * Does the namespace allow subpages?
  227. *
  228. * @param $index int Index to check
  229. * @return bool
  230. */
  231. public static function hasSubpages( $index ) {
  232. global $wgNamespacesWithSubpages;
  233. return !empty( $wgNamespacesWithSubpages[$index] );
  234. }
  235. /**
  236. * Get a list of all namespace indices which are considered to contain content
  237. * @return array of namespace indices
  238. */
  239. public static function getContentNamespaces() {
  240. global $wgContentNamespaces;
  241. if( !is_array( $wgContentNamespaces ) || $wgContentNamespaces === array() ) {
  242. return NS_MAIN;
  243. } elseif ( !in_array( NS_MAIN, $wgContentNamespaces ) ) {
  244. // always force NS_MAIN to be part of array (to match the algorithm used by isContent)
  245. return array_merge( array( NS_MAIN ), $wgContentNamespaces );
  246. } else {
  247. return $wgContentNamespaces;
  248. }
  249. }
  250. /**
  251. * Is the namespace first-letter capitalized?
  252. *
  253. * @param $index int Index to check
  254. * @return bool
  255. */
  256. public static function isCapitalized( $index ) {
  257. global $wgCapitalLinks, $wgCapitalLinkOverrides;
  258. // Turn NS_MEDIA into NS_FILE
  259. $index = $index === NS_MEDIA ? NS_FILE : $index;
  260. // Make sure to get the subject of our namespace
  261. $index = self::getSubject( $index );
  262. // Some namespaces are special and should always be upper case
  263. if ( in_array( $index, self::$alwaysCapitalizedNamespaces ) ) {
  264. return true;
  265. }
  266. if ( isset( $wgCapitalLinkOverrides[ $index ] ) ) {
  267. // $wgCapitalLinkOverrides is explicitly set
  268. return $wgCapitalLinkOverrides[ $index ];
  269. }
  270. // Default to the global setting
  271. return $wgCapitalLinks;
  272. }
  273. /**
  274. * Does the namespace (potentially) have different aliases for different
  275. * genders. Not all languages make a distinction here.
  276. *
  277. * @since 1.18
  278. * @param $index int Index to check
  279. * @return bool
  280. */
  281. public static function hasGenderDistinction( $index ) {
  282. return $index == NS_USER || $index == NS_USER_TALK;
  283. }
  284. }