[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
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 /** 24 * This is a utility class with only static functions 25 * for dealing with namespaces that encodes all the 26 * "magic" behaviors of them based on index. The textual 27 * names of the namespaces are handled by Language.php. 28 * 29 * These are synonyms for the names given in the language file 30 * Users and translators should not change them 31 * 32 */ 33 class MWNamespace { 34 35 /** 36 * These namespaces should always be first-letter capitalized, now and 37 * forevermore. Historically, they could've probably been lowercased too, 38 * but some things are just too ingrained now. :) 39 */ 40 private static $alwaysCapitalizedNamespaces = array( NS_SPECIAL, NS_USER, NS_MEDIAWIKI ); 41 42 /** 43 * Throw an exception when trying to get the subject or talk page 44 * for a given namespace where it does not make sense. 45 * Special namespaces are defined in includes/Defines.php and have 46 * a value below 0 (ex: NS_SPECIAL = -1 , NS_MEDIA = -2) 47 * 48 * @param int $index 49 * @param string $method 50 * 51 * @throws MWException 52 * @return bool 53 */ 54 private static function isMethodValidFor( $index, $method ) { 55 if ( $index < NS_MAIN ) { 56 throw new MWException( "$method does not make any sense for given namespace $index" ); 57 } 58 return true; 59 } 60 61 /** 62 * Can pages in the given namespace be moved? 63 * 64 * @param int $index Namespace index 65 * @return bool 66 */ 67 public static function isMovable( $index ) { 68 global $wgAllowImageMoving; 69 70 $result = !( $index < NS_MAIN || ( $index == NS_FILE && !$wgAllowImageMoving ) ); 71 72 /** 73 * @since 1.20 74 */ 75 wfRunHooks( 'NamespaceIsMovable', array( $index, &$result ) ); 76 77 return $result; 78 } 79 80 /** 81 * Is the given namespace is a subject (non-talk) namespace? 82 * 83 * @param int $index Namespace index 84 * @return bool 85 * @since 1.19 86 */ 87 public static function isSubject( $index ) { 88 return !self::isTalk( $index ); 89 } 90 91 /** 92 * Is the given namespace a talk namespace? 93 * 94 * @param int $index Namespace index 95 * @return bool 96 */ 97 public static function isTalk( $index ) { 98 return $index > NS_MAIN 99 && $index % 2; 100 } 101 102 /** 103 * Get the talk namespace index for a given namespace 104 * 105 * @param int $index Namespace index 106 * @return int 107 */ 108 public static function getTalk( $index ) { 109 self::isMethodValidFor( $index, __METHOD__ ); 110 return self::isTalk( $index ) 111 ? $index 112 : $index + 1; 113 } 114 115 /** 116 * Get the subject namespace index for a given namespace 117 * Special namespaces (NS_MEDIA, NS_SPECIAL) are always the subject. 118 * 119 * @param int $index Namespace index 120 * @return int 121 */ 122 public static function getSubject( $index ) { 123 # Handle special namespaces 124 if ( $index < NS_MAIN ) { 125 return $index; 126 } 127 128 return self::isTalk( $index ) 129 ? $index - 1 130 : $index; 131 } 132 133 /** 134 * Get the associated namespace. 135 * For talk namespaces, returns the subject (non-talk) namespace 136 * For subject (non-talk) namespaces, returns the talk namespace 137 * 138 * @param int $index Namespace index 139 * @return int|null If no associated namespace could be found 140 */ 141 public static function getAssociated( $index ) { 142 self::isMethodValidFor( $index, __METHOD__ ); 143 144 if ( self::isSubject( $index ) ) { 145 return self::getTalk( $index ); 146 } elseif ( self::isTalk( $index ) ) { 147 return self::getSubject( $index ); 148 } else { 149 return null; 150 } 151 } 152 153 /** 154 * Returns whether the specified namespace exists 155 * 156 * @param int $index 157 * 158 * @return bool 159 * @since 1.19 160 */ 161 public static function exists( $index ) { 162 $nslist = self::getCanonicalNamespaces(); 163 return isset( $nslist[$index] ); 164 } 165 166 /** 167 * Returns whether the specified namespaces are the same namespace 168 * 169 * @note It's possible that in the future we may start using something 170 * other than just namespace indexes. Under that circumstance making use 171 * of this function rather than directly doing comparison will make 172 * sure that code will not potentially break. 173 * 174 * @param int $ns1 The first namespace index 175 * @param int $ns2 The second namespace index 176 * 177 * @return bool 178 * @since 1.19 179 */ 180 public static function equals( $ns1, $ns2 ) { 181 return $ns1 == $ns2; 182 } 183 184 /** 185 * Returns whether the specified namespaces share the same subject. 186 * eg: NS_USER and NS_USER wil return true, as well 187 * NS_USER and NS_USER_TALK will return true. 188 * 189 * @param int $ns1 The first namespace index 190 * @param int $ns2 The second namespace index 191 * 192 * @return bool 193 * @since 1.19 194 */ 195 public static function subjectEquals( $ns1, $ns2 ) { 196 return self::getSubject( $ns1 ) == self::getSubject( $ns2 ); 197 } 198 199 /** 200 * Returns array of all defined namespaces with their canonical 201 * (English) names. 202 * 203 * @param bool $rebuild Rebuild namespace list (default = false). Used for testing. 204 * 205 * @return array 206 * @since 1.17 207 */ 208 public static function getCanonicalNamespaces( $rebuild = false ) { 209 static $namespaces = null; 210 if ( $namespaces === null || $rebuild ) { 211 global $wgExtraNamespaces, $wgCanonicalNamespaceNames; 212 $namespaces = array( NS_MAIN => '' ) + $wgCanonicalNamespaceNames; 213 if ( is_array( $wgExtraNamespaces ) ) { 214 $namespaces += $wgExtraNamespaces; 215 } 216 wfRunHooks( 'CanonicalNamespaces', array( &$namespaces ) ); 217 } 218 return $namespaces; 219 } 220 221 /** 222 * Returns the canonical (English) name for a given index 223 * 224 * @param int $index Namespace index 225 * @return string|bool If no canonical definition. 226 */ 227 public static function getCanonicalName( $index ) { 228 $nslist = self::getCanonicalNamespaces(); 229 if ( isset( $nslist[$index] ) ) { 230 return $nslist[$index]; 231 } else { 232 return false; 233 } 234 } 235 236 /** 237 * Returns the index for a given canonical name, or NULL 238 * The input *must* be converted to lower case first 239 * 240 * @param string $name Namespace name 241 * @return int 242 */ 243 public static function getCanonicalIndex( $name ) { 244 static $xNamespaces = false; 245 if ( $xNamespaces === false ) { 246 $xNamespaces = array(); 247 foreach ( self::getCanonicalNamespaces() as $i => $text ) { 248 $xNamespaces[strtolower( $text )] = $i; 249 } 250 } 251 if ( array_key_exists( $name, $xNamespaces ) ) { 252 return $xNamespaces[$name]; 253 } else { 254 return null; 255 } 256 } 257 258 /** 259 * Returns an array of the namespaces (by integer id) that exist on the 260 * wiki. Used primarily by the api in help documentation. 261 * @return array 262 */ 263 public static function getValidNamespaces() { 264 static $mValidNamespaces = null; 265 266 if ( is_null( $mValidNamespaces ) ) { 267 foreach ( array_keys( self::getCanonicalNamespaces() ) as $ns ) { 268 if ( $ns >= 0 ) { 269 $mValidNamespaces[] = $ns; 270 } 271 } 272 } 273 274 return $mValidNamespaces; 275 } 276 277 /** 278 * Can this namespace ever have a talk namespace? 279 * 280 * @param int $index Namespace index 281 * @return bool 282 */ 283 public static function canTalk( $index ) { 284 return $index >= NS_MAIN; 285 } 286 287 /** 288 * Does this namespace contain content, for the purposes of calculating 289 * statistics, etc? 290 * 291 * @param int $index Index to check 292 * @return bool 293 */ 294 public static function isContent( $index ) { 295 global $wgContentNamespaces; 296 return $index == NS_MAIN || in_array( $index, $wgContentNamespaces ); 297 } 298 299 /** 300 * Can pages in a namespace be watched? 301 * 302 * @param int $index 303 * @return bool 304 */ 305 public static function isWatchable( $index ) { 306 return $index >= NS_MAIN; 307 } 308 309 /** 310 * Does the namespace allow subpages? 311 * 312 * @param int $index Index to check 313 * @return bool 314 */ 315 public static function hasSubpages( $index ) { 316 global $wgNamespacesWithSubpages; 317 return !empty( $wgNamespacesWithSubpages[$index] ); 318 } 319 320 /** 321 * Get a list of all namespace indices which are considered to contain content 322 * @return array Array of namespace indices 323 */ 324 public static function getContentNamespaces() { 325 global $wgContentNamespaces; 326 if ( !is_array( $wgContentNamespaces ) || $wgContentNamespaces === array() ) { 327 return array( NS_MAIN ); 328 } elseif ( !in_array( NS_MAIN, $wgContentNamespaces ) ) { 329 // always force NS_MAIN to be part of array (to match the algorithm used by isContent) 330 return array_merge( array( NS_MAIN ), $wgContentNamespaces ); 331 } else { 332 return $wgContentNamespaces; 333 } 334 } 335 336 /** 337 * List all namespace indices which are considered subject, aka not a talk 338 * or special namespace. See also MWNamespace::isSubject 339 * 340 * @return array Array of namespace indices 341 */ 342 public static function getSubjectNamespaces() { 343 return array_filter( 344 MWNamespace::getValidNamespaces(), 345 'MWNamespace::isSubject' 346 ); 347 } 348 349 /** 350 * List all namespace indices which are considered talks, aka not a subject 351 * or special namespace. See also MWNamespace::isTalk 352 * 353 * @return array Array of namespace indices 354 */ 355 public static function getTalkNamespaces() { 356 return array_filter( 357 MWNamespace::getValidNamespaces(), 358 'MWNamespace::isTalk' 359 ); 360 } 361 362 /** 363 * Is the namespace first-letter capitalized? 364 * 365 * @param int $index Index to check 366 * @return bool 367 */ 368 public static function isCapitalized( $index ) { 369 global $wgCapitalLinks, $wgCapitalLinkOverrides; 370 // Turn NS_MEDIA into NS_FILE 371 $index = $index === NS_MEDIA ? NS_FILE : $index; 372 373 // Make sure to get the subject of our namespace 374 $index = self::getSubject( $index ); 375 376 // Some namespaces are special and should always be upper case 377 if ( in_array( $index, self::$alwaysCapitalizedNamespaces ) ) { 378 return true; 379 } 380 if ( isset( $wgCapitalLinkOverrides[$index] ) ) { 381 // $wgCapitalLinkOverrides is explicitly set 382 return $wgCapitalLinkOverrides[$index]; 383 } 384 // Default to the global setting 385 return $wgCapitalLinks; 386 } 387 388 /** 389 * Does the namespace (potentially) have different aliases for different 390 * genders. Not all languages make a distinction here. 391 * 392 * @since 1.18 393 * @param int $index Index to check 394 * @return bool 395 */ 396 public static function hasGenderDistinction( $index ) { 397 return $index == NS_USER || $index == NS_USER_TALK; 398 } 399 400 /** 401 * It is not possible to use pages from this namespace as template? 402 * 403 * @since 1.20 404 * @param int $index Index to check 405 * @return bool 406 */ 407 public static function isNonincludable( $index ) { 408 global $wgNonincludableNamespaces; 409 return $wgNonincludableNamespaces && in_array( $index, $wgNonincludableNamespaces ); 410 } 411 412 /** 413 * Get the default content model for a namespace 414 * This does not mean that all pages in that namespace have the model 415 * 416 * @since 1.21 417 * @param int $index Index to check 418 * @return null|string Default model name for the given namespace, if set 419 */ 420 public static function getNamespaceContentModel( $index ) { 421 global $wgNamespaceContentModels; 422 return isset( $wgNamespaceContentModels[$index] ) 423 ? $wgNamespaceContentModels[$index] 424 : null; 425 } 426 427 /** 428 * Determine which restriction levels it makes sense to use in a namespace, 429 * optionally filtered by a user's rights. 430 * 431 * @since 1.23 432 * @param int $index Index to check 433 * @param User $user User to check 434 * @return array 435 */ 436 public static function getRestrictionLevels( $index, User $user = null ) { 437 global $wgNamespaceProtection, $wgRestrictionLevels; 438 439 if ( !isset( $wgNamespaceProtection[$index] ) ) { 440 // All levels are valid if there's no namespace restriction. 441 // But still filter by user, if necessary 442 $levels = $wgRestrictionLevels; 443 if ( $user ) { 444 $levels = array_values( array_filter( $levels, function ( $level ) use ( $user ) { 445 $right = $level; 446 if ( $right == 'sysop' ) { 447 $right = 'editprotected'; // BC 448 } 449 if ( $right == 'autoconfirmed' ) { 450 $right = 'editsemiprotected'; // BC 451 } 452 return ( $right == '' || $user->isAllowed( $right ) ); 453 } ) ); 454 } 455 return $levels; 456 } 457 458 // First, get the list of groups that can edit this namespace. 459 $namespaceGroups = array(); 460 $combine = 'array_merge'; 461 foreach ( (array)$wgNamespaceProtection[$index] as $right ) { 462 if ( $right == 'sysop' ) { 463 $right = 'editprotected'; // BC 464 } 465 if ( $right == 'autoconfirmed' ) { 466 $right = 'editsemiprotected'; // BC 467 } 468 if ( $right != '' ) { 469 $namespaceGroups = call_user_func( $combine, $namespaceGroups, 470 User::getGroupsWithPermission( $right ) ); 471 $combine = 'array_intersect'; 472 } 473 } 474 475 // Now, keep only those restriction levels where there is at least one 476 // group that can edit the namespace but would be blocked by the 477 // restriction. 478 $usableLevels = array( '' ); 479 foreach ( $wgRestrictionLevels as $level ) { 480 $right = $level; 481 if ( $right == 'sysop' ) { 482 $right = 'editprotected'; // BC 483 } 484 if ( $right == 'autoconfirmed' ) { 485 $right = 'editsemiprotected'; // BC 486 } 487 if ( $right != '' && ( !$user || $user->isAllowed( $right ) ) && 488 array_diff( $namespaceGroups, User::getGroupsWithPermission( $right ) ) 489 ) { 490 $usableLevels[] = $level; 491 } 492 } 493 494 return $usableLevels; 495 } 496 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |