Index: trunk/phase3/maintenance/updateSpecialPages.php |
— | — | @@ -78,7 +78,7 @@ |
79 | 79 | continue; |
80 | 80 | } |
81 | 81 | |
82 | | - $specialObj = SpecialPage::getPage( $special ); |
| 82 | + $specialObj = SpecialPageFactory::getPage( $special ); |
83 | 83 | if ( !$specialObj ) { |
84 | 84 | $this->output( "No such special page: $special\n" ); |
85 | 85 | exit; |
Index: trunk/phase3/includes/SpecialPageFactory.php |
— | — | @@ -0,0 +1,543 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * SpecialPage: handling special pages and lists thereof. |
| 5 | + * |
| 6 | + * To add a special page in an extension, add to $wgSpecialPages either |
| 7 | + * an object instance or an array containing the name and constructor |
| 8 | + * parameters. The latter is preferred for performance reasons. |
| 9 | + * |
| 10 | + * The object instantiated must be either an instance of SpecialPage or a |
| 11 | + * sub-class thereof. It must have an execute() method, which sends the HTML |
| 12 | + * for the special page to $wgOut. The parent class has an execute() method |
| 13 | + * which distributes the call to the historical global functions. Additionally, |
| 14 | + * execute() also checks if the user has the necessary access privileges |
| 15 | + * and bails out if not. |
| 16 | + * |
| 17 | + * To add a core special page, use the similar static list in |
| 18 | + * SpecialPage::$mList. To remove a core static special page at runtime, use |
| 19 | + * a SpecialPage_initList hook. |
| 20 | + * |
| 21 | + * @file |
| 22 | + * @ingroup SpecialPage |
| 23 | + * @defgroup SpecialPage SpecialPage |
| 24 | + */ |
| 25 | + |
| 26 | +/** |
| 27 | + * Factory for handling the special page list and generating SpecialPage objects |
| 28 | + * @ingroup SpecialPage |
| 29 | + */ |
| 30 | +class SpecialPageFactory { |
| 31 | + |
| 32 | + /** |
| 33 | + * List of special page names to the subclass of SpecialPage which handles them. |
| 34 | + */ |
| 35 | + private static $mList = array( |
| 36 | + // Maintenance Reports |
| 37 | + 'BrokenRedirects' => 'BrokenRedirectsPage', |
| 38 | + 'Deadendpages' => 'DeadendpagesPage', |
| 39 | + 'DoubleRedirects' => 'DoubleRedirectsPage', |
| 40 | + 'Longpages' => 'LongpagesPage', |
| 41 | + 'Ancientpages' => 'AncientpagesPage', |
| 42 | + 'Lonelypages' => 'LonelypagesPage', |
| 43 | + 'Fewestrevisions' => 'FewestrevisionsPage', |
| 44 | + 'Withoutinterwiki' => 'WithoutinterwikiPage', |
| 45 | + 'Protectedpages' => 'SpecialProtectedpages', |
| 46 | + 'Protectedtitles' => 'SpecialProtectedtitles', |
| 47 | + 'Shortpages' => 'ShortpagesPage', |
| 48 | + 'Uncategorizedcategories' => 'UncategorizedcategoriesPage', |
| 49 | + 'Uncategorizedimages' => 'UncategorizedimagesPage', |
| 50 | + 'Uncategorizedpages' => 'UncategorizedpagesPage', |
| 51 | + 'Uncategorizedtemplates' => 'UncategorizedtemplatesPage', |
| 52 | + 'Unusedcategories' => 'UnusedcategoriesPage', |
| 53 | + 'Unusedimages' => 'UnusedimagesPage', |
| 54 | + 'Unusedtemplates' => 'UnusedtemplatesPage', |
| 55 | + 'Unwatchedpages' => 'UnwatchedpagesPage', |
| 56 | + 'Wantedcategories' => 'WantedcategoriesPage', |
| 57 | + 'Wantedfiles' => 'WantedfilesPage', |
| 58 | + 'Wantedpages' => 'WantedpagesPage', |
| 59 | + 'Wantedtemplates' => 'WantedtemplatesPage', |
| 60 | + |
| 61 | + // List of pages |
| 62 | + 'Allpages' => 'SpecialAllpages', |
| 63 | + 'Prefixindex' => 'SpecialPrefixindex', |
| 64 | + 'Categories' => 'SpecialCategories', |
| 65 | + 'Disambiguations' => 'DisambiguationsPage', |
| 66 | + 'Listredirects' => 'ListredirectsPage', |
| 67 | + |
| 68 | + // Login/create account |
| 69 | + 'Userlogin' => 'LoginForm', |
| 70 | + 'CreateAccount' => 'SpecialCreateAccount', |
| 71 | + |
| 72 | + // Users and rights |
| 73 | + 'Block' => 'SpecialBlock', |
| 74 | + 'Unblock' => 'SpecialUnblock', |
| 75 | + 'BlockList' => 'SpecialBlockList', |
| 76 | + 'Resetpass' => 'SpecialResetpass', |
| 77 | + 'DeletedContributions' => 'DeletedContributionsPage', |
| 78 | + 'Preferences' => 'SpecialPreferences', |
| 79 | + 'Contributions' => 'SpecialContributions', |
| 80 | + 'Listgrouprights' => 'SpecialListGroupRights', |
| 81 | + 'Listusers' => 'SpecialListUsers' , |
| 82 | + 'Listadmins' => 'SpecialListAdmins', |
| 83 | + 'Listbots' => 'SpecialListBots', |
| 84 | + 'Activeusers' => 'SpecialActiveUsers', |
| 85 | + 'Userrights' => 'UserrightsPage', |
| 86 | + 'EditWatchlist' => 'SpecialEditWatchlist', |
| 87 | + |
| 88 | + // Recent changes and logs |
| 89 | + 'Newimages' => 'SpecialNewFiles', |
| 90 | + 'Log' => 'SpecialLog', |
| 91 | + 'Watchlist' => 'SpecialWatchlist', |
| 92 | + 'Newpages' => 'SpecialNewpages', |
| 93 | + 'Recentchanges' => 'SpecialRecentchanges', |
| 94 | + 'Recentchangeslinked' => 'SpecialRecentchangeslinked', |
| 95 | + 'Tags' => 'SpecialTags', |
| 96 | + |
| 97 | + // Media reports and uploads |
| 98 | + 'Listfiles' => 'SpecialListFiles', |
| 99 | + 'Filepath' => 'SpecialFilepath', |
| 100 | + 'MIMEsearch' => 'MIMEsearchPage', |
| 101 | + 'FileDuplicateSearch' => 'FileDuplicateSearchPage', |
| 102 | + 'Upload' => 'SpecialUpload', |
| 103 | + 'UploadStash' => 'SpecialUploadStash', |
| 104 | + |
| 105 | + // Wiki data and tools |
| 106 | + 'Statistics' => 'SpecialStatistics', |
| 107 | + 'Allmessages' => 'SpecialAllmessages', |
| 108 | + 'Version' => 'SpecialVersion', |
| 109 | + 'Lockdb' => 'SpecialLockdb', |
| 110 | + 'Unlockdb' => 'SpecialUnlockdb', |
| 111 | + |
| 112 | + // Redirecting special pages |
| 113 | + 'LinkSearch' => 'LinkSearchPage', |
| 114 | + 'Randompage' => 'Randompage', |
| 115 | + 'Randomredirect' => 'SpecialRandomredirect', |
| 116 | + |
| 117 | + // High use pages |
| 118 | + 'Mostlinkedcategories' => 'MostlinkedCategoriesPage', |
| 119 | + 'Mostimages' => 'MostimagesPage', |
| 120 | + 'Mostlinked' => 'MostlinkedPage', |
| 121 | + 'Mostlinkedtemplates' => 'MostlinkedTemplatesPage', |
| 122 | + 'Mostcategories' => 'MostcategoriesPage', |
| 123 | + 'Mostrevisions' => 'MostrevisionsPage', |
| 124 | + |
| 125 | + // Page tools |
| 126 | + 'ComparePages' => 'SpecialComparePages', |
| 127 | + 'Export' => 'SpecialExport', |
| 128 | + 'Import' => 'SpecialImport', |
| 129 | + 'Undelete' => 'SpecialUndelete', |
| 130 | + 'Whatlinkshere' => 'SpecialWhatlinkshere', |
| 131 | + 'MergeHistory' => 'SpecialMergeHistory', |
| 132 | + |
| 133 | + // Other |
| 134 | + 'Booksources' => 'SpecialBookSources', |
| 135 | + |
| 136 | + // Unlisted / redirects |
| 137 | + 'Blankpage' => 'SpecialBlankpage', |
| 138 | + 'Blockme' => 'SpecialBlockme', |
| 139 | + 'Emailuser' => 'SpecialEmailUser', |
| 140 | + 'Movepage' => 'MovePageForm', |
| 141 | + 'Mycontributions' => 'SpecialMycontributions', |
| 142 | + 'Mypage' => 'SpecialMypage', |
| 143 | + 'Mytalk' => 'SpecialMytalk', |
| 144 | + 'Myuploads' => 'SpecialMyuploads', |
| 145 | + 'PermanentLink' => 'SpecialPermanentLink', |
| 146 | + 'Revisiondelete' => 'SpecialRevisionDelete', |
| 147 | + 'Specialpages' => 'SpecialSpecialpages', |
| 148 | + 'Userlogout' => 'SpecialUserlogout', |
| 149 | + ); |
| 150 | + |
| 151 | + private static $mAliases; |
| 152 | + |
| 153 | + /** |
| 154 | + * Initialise the special page list |
| 155 | + * This must be called before accessing SpecialPage::$mList |
| 156 | + */ |
| 157 | + static function getList() { |
| 158 | + global $wgSpecialPages; |
| 159 | + global $wgDisableCounters, $wgDisableInternalSearch, $wgEmailAuthentication; |
| 160 | + |
| 161 | + if ( !is_object( self::$mList ) ) { |
| 162 | + wfProfileIn( __METHOD__ ); |
| 163 | + |
| 164 | + if ( !$wgDisableCounters ) { |
| 165 | + self::$mList['Popularpages'] = 'PopularpagesPage'; |
| 166 | + } |
| 167 | + |
| 168 | + if ( !$wgDisableInternalSearch ) { |
| 169 | + self::$mList['Search'] = 'SpecialSearch'; |
| 170 | + } |
| 171 | + |
| 172 | + if ( $wgEmailAuthentication ) { |
| 173 | + self::$mList['Confirmemail'] = 'EmailConfirmation'; |
| 174 | + self::$mList['Invalidateemail'] = 'EmailInvalidation'; |
| 175 | + } |
| 176 | + |
| 177 | + // Add extension special pages |
| 178 | + self::$mList = array_merge( self::$mList, $wgSpecialPages ); |
| 179 | + |
| 180 | + // Run hooks |
| 181 | + // This hook can be used to remove undesired built-in special pages |
| 182 | + wfRunHooks( 'SpecialPage_initList', array( &self::$mList ) ); |
| 183 | + |
| 184 | + // Cast to object: func()[$key] doesn't work, but func()->$key does |
| 185 | + settype( self::$mList, 'object' ); |
| 186 | + |
| 187 | + wfProfileOut( __METHOD__ ); |
| 188 | + } |
| 189 | + return self::$mList; |
| 190 | + } |
| 191 | + |
| 192 | + static function getAliasList() { |
| 193 | + if ( !is_object( self::$mAliases ) ) { |
| 194 | + global $wgContLang; |
| 195 | + $aliases = $wgContLang->getSpecialPageAliases(); |
| 196 | + |
| 197 | + // Objects are passed by reference by default, need to create a copy |
| 198 | + $missingPages = clone self::getList(); |
| 199 | + |
| 200 | + self::$mAliases = array(); |
| 201 | + foreach ( $aliases as $realName => $aliasList ) { |
| 202 | + foreach ( $aliasList as $alias ) { |
| 203 | + self::$mAliases[$wgContLang->caseFold( $alias )] = $realName; |
| 204 | + } |
| 205 | + unset( $missingPages->$realName ); |
| 206 | + } |
| 207 | + foreach ( $missingPages as $name => $stuff ) { |
| 208 | + self::$mAliases[$wgContLang->caseFold( $name )] = $name; |
| 209 | + } |
| 210 | + |
| 211 | + // Cast to object: func()[$key] doesn't work, but func()->$key does |
| 212 | + self::$mAliases = (object)self::$mAliases; |
| 213 | + } |
| 214 | + return self::$mAliases; |
| 215 | + } |
| 216 | + |
| 217 | + /** |
| 218 | + * Given a special page name with a possible subpage, return an array |
| 219 | + * where the first element is the special page name and the second is the |
| 220 | + * subpage. |
| 221 | + * |
| 222 | + * @param $alias String |
| 223 | + * @return Array( String, String|null ), or array( null, null ) if the page is invalid |
| 224 | + */ |
| 225 | + public static function resolveAlias( $alias ) { |
| 226 | + global $wgContLang; |
| 227 | + $bits = explode( '/', $alias, 2 ); |
| 228 | + |
| 229 | + $caseFoldedAlias = $wgContLang->caseFold( $bits[0] ); |
| 230 | + $caseFoldedAlias = str_replace( ' ', '_', $caseFoldedAlias ); |
| 231 | + if ( isset( self::getAliasList()->$caseFoldedAlias ) ) { |
| 232 | + $name = self::getAliasList()->$caseFoldedAlias; |
| 233 | + } else { |
| 234 | + return array( null, null ); |
| 235 | + } |
| 236 | + |
| 237 | + if ( !isset( $bits[1] ) ) { // bug 2087 |
| 238 | + $par = null; |
| 239 | + } else { |
| 240 | + $par = $bits[1]; |
| 241 | + } |
| 242 | + |
| 243 | + return array( $name, $par ); |
| 244 | + } |
| 245 | + |
| 246 | + /** |
| 247 | + * Add a page to a certain display group for Special:SpecialPages |
| 248 | + * |
| 249 | + * @param $page Mixed: SpecialPage or string |
| 250 | + * @param $group String |
| 251 | + */ |
| 252 | + public static function setGroup( $page, $group ) { |
| 253 | + global $wgSpecialPageGroups; |
| 254 | + $name = is_object( $page ) ? $page->mName : $page; |
| 255 | + $wgSpecialPageGroups[$name] = $group; |
| 256 | + } |
| 257 | + |
| 258 | + /** |
| 259 | + * Add a page to a certain display group for Special:SpecialPages |
| 260 | + * |
| 261 | + * @param $page SpecialPage |
| 262 | + */ |
| 263 | + public static function getGroup( &$page ) { |
| 264 | + global $wgSpecialPageGroups; |
| 265 | + static $specialPageGroupsCache = array(); |
| 266 | + if ( isset( $specialPageGroupsCache[$page->mName] ) ) { |
| 267 | + return $specialPageGroupsCache[$page->mName]; |
| 268 | + } |
| 269 | + $msg = wfMessage( 'specialpages-specialpagegroup-' . strtolower( $page->mName ) ); |
| 270 | + if ( !$msg->isBlank() ) { |
| 271 | + $group = $msg->text(); |
| 272 | + } else { |
| 273 | + $group = isset( $wgSpecialPageGroups[$page->mName] ) |
| 274 | + ? $wgSpecialPageGroups[$page->mName] |
| 275 | + : '-'; |
| 276 | + } |
| 277 | + if ( $group == '-' ) { |
| 278 | + $group = 'other'; |
| 279 | + } |
| 280 | + $specialPageGroupsCache[$page->mName] = $group; |
| 281 | + return $group; |
| 282 | + } |
| 283 | + |
| 284 | + /** |
| 285 | + * Check if a given name exist as a special page or as a special page alias |
| 286 | + * |
| 287 | + * @param $name String: name of a special page |
| 288 | + * @return Boolean: true if a special page exists with this name |
| 289 | + */ |
| 290 | + public static function exists( $name ) { |
| 291 | + list( $title, /*...*/ ) = self::resolveAlias( $name ); |
| 292 | + return property_exists( self::getList(), $title ); |
| 293 | + } |
| 294 | + |
| 295 | + /** |
| 296 | + * Find the object with a given name and return it (or NULL) |
| 297 | + * |
| 298 | + * @param $name String Special page name, may be localised and/or an alias |
| 299 | + * @return SpecialPage object or null if the page doesn't exist |
| 300 | + */ |
| 301 | + public static function getPage( $name ) { |
| 302 | + list( $realName, /*...*/ ) = self::resolveAlias( $name ); |
| 303 | + if ( property_exists( self::getList(), $realName ) ) { |
| 304 | + $rec = self::getList()->$realName; |
| 305 | + if ( is_string( $rec ) ) { |
| 306 | + $className = $rec; |
| 307 | + self::getList()->$realName = new $className; |
| 308 | + } elseif ( is_array( $rec ) ) { |
| 309 | + // @deprecated, officially since 1.18, unofficially since forever |
| 310 | + wfDebug( "Array syntax for \$wgSpecialPages is deprecated, define a subclass of SpecialPage instead." ); |
| 311 | + $className = array_shift( $rec ); |
| 312 | + self::getList()->$realName = MWFunction::newObj( $className, $rec ); |
| 313 | + } |
| 314 | + return self::getList()->$realName; |
| 315 | + } else { |
| 316 | + return null; |
| 317 | + } |
| 318 | + } |
| 319 | + |
| 320 | + /** |
| 321 | + * Return categorised listable special pages which are available |
| 322 | + * for the current user, and everyone. |
| 323 | + * |
| 324 | + * @return Array( String => Specialpage ) |
| 325 | + */ |
| 326 | + public static function getUsablePages() { |
| 327 | + global $wgUser; |
| 328 | + $pages = array(); |
| 329 | + foreach ( self::getList() as $name => $rec ) { |
| 330 | + $page = self::getPage( $name ); |
| 331 | + if ( $page->isListed() |
| 332 | + && ( |
| 333 | + !$page->isRestricted() |
| 334 | + || $page->userCanExecute( $wgUser ) |
| 335 | + ) |
| 336 | + ) { |
| 337 | + $pages[$name] = $page; |
| 338 | + } |
| 339 | + } |
| 340 | + return $pages; |
| 341 | + } |
| 342 | + |
| 343 | + /** |
| 344 | + * Return categorised listable special pages for all users |
| 345 | + * |
| 346 | + * @return Array( String => Specialpage ) |
| 347 | + */ |
| 348 | + public static function getRegularPages() { |
| 349 | + $pages = array(); |
| 350 | + foreach ( self::getList() as $name => $rec ) { |
| 351 | + $page = self::getPage( $name ); |
| 352 | + if ( $page->isListed() && !$page->isRestricted() ) { |
| 353 | + $pages[$name] = $page; |
| 354 | + } |
| 355 | + } |
| 356 | + return $pages; |
| 357 | + } |
| 358 | + |
| 359 | + /** |
| 360 | + * Return categorised listable special pages which are available |
| 361 | + * for the current user, but not for everyone |
| 362 | + * |
| 363 | + * @return Array( String => Specialpage ) |
| 364 | + */ |
| 365 | + public static function getRestrictedPages() { |
| 366 | + global $wgUser; |
| 367 | + $pages = array(); |
| 368 | + foreach ( self::getList() as $name => $rec ) { |
| 369 | + $page = self::getPage( $name ); |
| 370 | + if ( |
| 371 | + $page->isListed() |
| 372 | + && $page->isRestricted() |
| 373 | + && $page->userCanExecute( $wgUser ) |
| 374 | + ) { |
| 375 | + $pages[$name] = $page; |
| 376 | + } |
| 377 | + } |
| 378 | + return $pages; |
| 379 | + } |
| 380 | + |
| 381 | + /** |
| 382 | + * Execute a special page path. |
| 383 | + * The path may contain parameters, e.g. Special:Name/Params |
| 384 | + * Extracts the special page name and call the execute method, passing the parameters |
| 385 | + * |
| 386 | + * Returns a title object if the page is redirected, false if there was no such special |
| 387 | + * page, and true if it was successful. |
| 388 | + * |
| 389 | + * @param $title Title object |
| 390 | + * @param $context RequestContext |
| 391 | + * @param $including Bool output is being captured for use in {{special:whatever}} |
| 392 | + */ |
| 393 | + public static function executePath( Title &$title, RequestContext &$context, $including = false ) { |
| 394 | + wfProfileIn( __METHOD__ ); |
| 395 | + |
| 396 | + // FIXME: redirects broken due to this call |
| 397 | + $bits = explode( '/', $title->getDBkey(), 2 ); |
| 398 | + $name = $bits[0]; |
| 399 | + if ( !isset( $bits[1] ) ) { // bug 2087 |
| 400 | + $par = null; |
| 401 | + } else { |
| 402 | + $par = $bits[1]; |
| 403 | + } |
| 404 | + $page = self::getPage( $name ); |
| 405 | + // Nonexistent? |
| 406 | + if ( !$page ) { |
| 407 | + $context->output->setArticleRelated( false ); |
| 408 | + $context->output->setRobotPolicy( 'noindex,nofollow' ); |
| 409 | + $context->output->setStatusCode( 404 ); |
| 410 | + $context->output->showErrorPage( 'nosuchspecialpage', 'nospecialpagetext' ); |
| 411 | + wfProfileOut( __METHOD__ ); |
| 412 | + return false; |
| 413 | + } |
| 414 | + |
| 415 | + // Page exists, set the context |
| 416 | + $page->setContext( $context ); |
| 417 | + |
| 418 | + // Check for redirect |
| 419 | + if ( !$including ) { |
| 420 | + $redirect = $page->getRedirect( $par ); |
| 421 | + $query = $page->getRedirectQuery(); |
| 422 | + if ( $redirect instanceof Title ) { |
| 423 | + $url = $redirect->getFullUrl( $query ); |
| 424 | + $context->output->redirect( $url ); |
| 425 | + wfProfileOut( __METHOD__ ); |
| 426 | + return $redirect; |
| 427 | + } elseif ( $redirect === true ) { |
| 428 | + global $wgScript; |
| 429 | + $url = $wgScript . '?' . wfArrayToCGI( $query ); |
| 430 | + $context->output->redirect( $url ); |
| 431 | + wfProfileOut( __METHOD__ ); |
| 432 | + return $redirect; |
| 433 | + } |
| 434 | + |
| 435 | + // Redirect to canonical alias for GET commands |
| 436 | + // Not for POST, we'd lose the post data, so it's best to just distribute |
| 437 | + // the request. Such POST requests are possible for old extensions that |
| 438 | + // generate self-links without being aware that their default name has |
| 439 | + // changed. |
| 440 | + if ( $name != $page->getLocalName() && !$context->request->wasPosted() ) { |
| 441 | + $query = $_GET; |
| 442 | + unset( $query['title'] ); |
| 443 | + $query = wfArrayToCGI( $query ); |
| 444 | + $title = $page->getTitle( $par ); |
| 445 | + $url = $title->getFullUrl( $query ); |
| 446 | + $context->output->redirect( $url ); |
| 447 | + wfProfileOut( __METHOD__ ); |
| 448 | + return $redirect; |
| 449 | + } else { |
| 450 | + $context->title = $page->getTitle(); |
| 451 | + } |
| 452 | + |
| 453 | + } elseif ( !$page->includable() ) { |
| 454 | + wfProfileOut( __METHOD__ ); |
| 455 | + return false; |
| 456 | + } |
| 457 | + |
| 458 | + $page->including( $including ); |
| 459 | + |
| 460 | + // Execute special page |
| 461 | + $profName = 'Special:' . $page->name(); |
| 462 | + wfProfileIn( $profName ); |
| 463 | + $page->execute( $par ); |
| 464 | + wfProfileOut( $profName ); |
| 465 | + wfProfileOut( __METHOD__ ); |
| 466 | + return true; |
| 467 | + } |
| 468 | + |
| 469 | + /** |
| 470 | + * Just like executePath() except it returns the HTML instead of outputting it |
| 471 | + * Returns false if there was no such special page, or a title object if it was |
| 472 | + * a redirect. |
| 473 | + * |
| 474 | + * @return String: HTML fragment |
| 475 | + */ |
| 476 | + static function capturePath( &$title ) { |
| 477 | + global $wgOut, $wgTitle; |
| 478 | + |
| 479 | + $oldTitle = $wgTitle; |
| 480 | + $oldOut = $wgOut; |
| 481 | + |
| 482 | + $context = new RequestContext; |
| 483 | + $context->setTitle( $title ); |
| 484 | + $wgOut = $context->getOutput(); |
| 485 | + |
| 486 | + $ret = self::executePath( $title, $context, true ); |
| 487 | + if ( $ret === true ) { |
| 488 | + $ret = $wgOut->getHTML(); |
| 489 | + } |
| 490 | + $wgTitle = $oldTitle; |
| 491 | + $wgOut = $oldOut; |
| 492 | + return $ret; |
| 493 | + } |
| 494 | + |
| 495 | + /** |
| 496 | + * Get the local name for a specified canonical name |
| 497 | + * |
| 498 | + * @param $name String |
| 499 | + * @param $subpage String|Bool |
| 500 | + * |
| 501 | + * @return String |
| 502 | + */ |
| 503 | + static function getLocalNameFor( $name, $subpage = false ) { |
| 504 | + global $wgContLang; |
| 505 | + $aliases = $wgContLang->getSpecialPageAliases(); |
| 506 | + if ( isset( $aliases[$name][0] ) ) { |
| 507 | + $name = $aliases[$name][0]; |
| 508 | + } else { |
| 509 | + // Try harder in case someone misspelled the correct casing |
| 510 | + $found = false; |
| 511 | + foreach ( $aliases as $n => $values ) { |
| 512 | + if ( strcasecmp( $name, $n ) === 0 ) { |
| 513 | + wfWarn( "Found alias defined for $n when searching for " . |
| 514 | + "special page aliases for $name. Case mismatch?" ); |
| 515 | + $name = $values[0]; |
| 516 | + $found = true; |
| 517 | + break; |
| 518 | + } |
| 519 | + } |
| 520 | + if ( !$found ) { |
| 521 | + wfWarn( "Did not find alias for special page '$name'. " . |
| 522 | + "Perhaps no aliases are defined for it?" ); |
| 523 | + } |
| 524 | + } |
| 525 | + if ( $subpage !== false && !is_null( $subpage ) ) { |
| 526 | + $name = "$name/$subpage"; |
| 527 | + } |
| 528 | + return $wgContLang->ucfirst( $name ); |
| 529 | + } |
| 530 | + |
| 531 | + /** |
| 532 | + * Get a title for a given alias |
| 533 | + * |
| 534 | + * @return Title or null if there is no such alias |
| 535 | + */ |
| 536 | + static function getTitleForAlias( $alias ) { |
| 537 | + $name = self::resolveAlias( $alias ); |
| 538 | + if ( $name ) { |
| 539 | + return self::getTitleFor( $name ); |
| 540 | + } else { |
| 541 | + return null; |
| 542 | + } |
| 543 | + } |
| 544 | +} |
\ No newline at end of file |
Property changes on: trunk/phase3/includes/SpecialPageFactory.php |
___________________________________________________________________ |
Added: svn:mergeinfo |
1 | 545 | Merged /branches/new-installer/phase3/includes/SpecialPage.php:r43664-66004 |
2 | 546 | Merged /branches/wmf-deployment/includes/SpecialPage.php:r53381 |
3 | 547 | Merged /branches/uploadwizard/phase3/includes/SpecialPage.php:r73550-75905 |
4 | 548 | Merged /branches/REL1_15/phase3/includes/SpecialPage.php:r51646 |
5 | 549 | Merged /branches/sqlite/includes/SpecialPage.php:r58211-58321 |
Added: svn:eol-style |
6 | 550 | + native |
Added: svn:keywords |
7 | 551 | + Author Date Id Revision |
Index: trunk/phase3/includes/PrefixSearch.php |
— | — | @@ -85,15 +85,13 @@ |
86 | 86 | |
87 | 87 | // Unlike SpecialPage itself, we want the canonical forms of both |
88 | 88 | // canonical and alias title forms... |
89 | | - SpecialPage::initList(); |
90 | | - SpecialPage::initAliasList(); |
91 | 89 | $keys = array(); |
92 | | - foreach( array_keys( SpecialPage::$mList ) as $page ) { |
| 90 | + foreach( SpecialPageFactory::getList() as $page => $class ) { |
93 | 91 | $keys[$wgContLang->caseFold( $page )] = $page; |
94 | 92 | } |
95 | 93 | |
96 | 94 | foreach( $wgContLang->getSpecialPageAliases() as $page => $aliases ) { |
97 | | - if( !array_key_exists( $page, SpecialPage::$mList ) ) {# bug 20885 |
| 95 | + if( !array_key_exists( $page, SpecialPageFactory::getList() ) ) {# bug 20885 |
98 | 96 | continue; |
99 | 97 | } |
100 | 98 | |
Index: trunk/phase3/includes/parser/Parser.php |
— | — | @@ -3252,7 +3252,7 @@ |
3253 | 3253 | && $this->mOptions->getAllowSpecialInclusion() |
3254 | 3254 | && $this->ot['html'] ) |
3255 | 3255 | { |
3256 | | - $text = SpecialPage::capturePath( $title ); |
| 3256 | + $text = SpecialPageFactory::capturePath( $title ); |
3257 | 3257 | if ( is_string( $text ) ) { |
3258 | 3258 | $found = true; |
3259 | 3259 | $isHTML = true; |
Index: trunk/phase3/includes/parser/CoreParserFunctions.php |
— | — | @@ -653,7 +653,7 @@ |
654 | 654 | } |
655 | 655 | |
656 | 656 | static function special( $parser, $text ) { |
657 | | - list( $page, $subpage ) = SpecialPage::resolveAliasWithSubpage( $text ); |
| 657 | + list( $page, $subpage ) = SpecialPageFactory::resolveAlias( $text ); |
658 | 658 | if ( $page ) { |
659 | 659 | $title = SpecialPage::getTitleFor( $page, $subpage ); |
660 | 660 | return $title; |
Index: trunk/phase3/includes/Linker.php |
— | — | @@ -376,7 +376,7 @@ |
377 | 377 | |
378 | 378 | static function normaliseSpecialPage( Title $title ) { |
379 | 379 | if ( $title->getNamespace() == NS_SPECIAL ) { |
380 | | - list( $name, $subpage ) = SpecialPage::resolveAliasWithSubpage( $title->getDBkey() ); |
| 380 | + list( $name, $subpage ) = SpecialPageFactory::resolveAlias( $title->getDBkey() ); |
381 | 381 | if ( !$name ) { |
382 | 382 | return $title; |
383 | 383 | } |
Index: trunk/phase3/includes/OutputPage.php |
— | — | @@ -2652,8 +2652,7 @@ |
2653 | 2653 | $ns = $title->getNamespace(); |
2654 | 2654 | $nsname = MWNamespace::exists( $ns ) ? MWNamespace::getCanonicalName( $ns ) : $title->getNsText(); |
2655 | 2655 | if ( $ns == NS_SPECIAL ) { |
2656 | | - $parts = SpecialPage::resolveAliasWithSubpage( $title->getDBkey() ); |
2657 | | - $canonicalName = $parts[0]; |
| 2656 | + list( $canonicalName, /*...*/ ) = SpecialPageFactory::resolveAlias( $title->getDBkey() ); |
2658 | 2657 | } else { |
2659 | 2658 | $canonicalName = false; # bug 21115 |
2660 | 2659 | } |
Index: trunk/phase3/includes/api/ApiQuery.php |
— | — | @@ -430,7 +430,7 @@ |
431 | 431 | ApiQueryBase::addTitleInfo( $vals, $title ); |
432 | 432 | $vals['special'] = ''; |
433 | 433 | if ( $title->getNamespace() == NS_SPECIAL && |
434 | | - !SpecialPage::exists( $title->getDbKey() ) ) { |
| 434 | + !SpecialPageFactory::exists( $title->getDbKey() ) ) { |
435 | 435 | $vals['missing'] = ''; |
436 | 436 | } elseif ( $title->getNamespace() == NS_MEDIA && |
437 | 437 | !wfFindFile( $title ) ) { |
Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -226,6 +226,7 @@ |
227 | 227 | 'SpecialMypage' => 'includes/SpecialPage.php', |
228 | 228 | 'SpecialMytalk' => 'includes/SpecialPage.php', |
229 | 229 | 'SpecialPage' => 'includes/SpecialPage.php', |
| 230 | + 'SpecialPageFactory' => 'includes/SpecialPageFactory.php', |
230 | 231 | 'SpecialRedirectToSpecial' => 'includes/SpecialPage.php', |
231 | 232 | 'SquidUpdate' => 'includes/SquidUpdate.php', |
232 | 233 | 'SquidPurgeClient' => 'includes/SquidPurgeClient.php', |
Index: trunk/phase3/includes/Wiki.php |
— | — | @@ -212,7 +212,7 @@ |
213 | 213 | && !count( array_diff( array_keys( $this->context->request->getValues() ), array( 'action', 'title' ) ) ) ) |
214 | 214 | { |
215 | 215 | if ( $this->context->title->getNamespace() == NS_SPECIAL ) { |
216 | | - list( $name, $subpage ) = SpecialPage::resolveAliasWithSubpage( $this->context->title->getDBkey() ); |
| 216 | + list( $name, $subpage ) = SpecialPageFactory::resolveAlias( $this->context->title->getDBkey() ); |
217 | 217 | if ( $name ) { |
218 | 218 | $this->context->title = SpecialPage::getTitleFor( $name, $subpage ); |
219 | 219 | } |
— | — | @@ -249,7 +249,7 @@ |
250 | 250 | // Special pages |
251 | 251 | } else if ( NS_SPECIAL == $this->context->title->getNamespace() ) { |
252 | 252 | // actions that need to be made when we have a special pages |
253 | | - SpecialPage::executePath( $this->context->title, $this->context ); |
| 253 | + SpecialPageFactory::executePath( $this->context->title, $this->context ); |
254 | 254 | } else { |
255 | 255 | // No match to special cases |
256 | 256 | wfProfileOut( __METHOD__ ); |
— | — | @@ -553,7 +553,7 @@ |
554 | 554 | break; |
555 | 555 | case 'revisiondelete': |
556 | 556 | // For show/hide submission from history page |
557 | | - $special = SpecialPage::getPage( 'Revisiondelete' ); |
| 557 | + $special = SpecialPageFactory::getPage( 'Revisiondelete' ); |
558 | 558 | $special->execute( '' ); |
559 | 559 | break; |
560 | 560 | default: |
Index: trunk/phase3/includes/ChangesList.php |
— | — | @@ -558,7 +558,7 @@ |
559 | 559 | $this->insertLog( $s, $logtitle, $rc->mAttribs['rc_log_type'] ); |
560 | 560 | // Log entries (old format) or log targets, and special pages |
561 | 561 | } elseif( $rc->mAttribs['rc_namespace'] == NS_SPECIAL ) { |
562 | | - list( $name, $subpage ) = SpecialPage::resolveAliasWithSubpage( $rc->mAttribs['rc_title'] ); |
| 562 | + list( $name, $subpage ) = SpecialPageFactory::resolveAlias( $rc->mAttribs['rc_title'] ); |
563 | 563 | if( $name == 'Log' ) { |
564 | 564 | $this->insertLog( $s, $rc->getTitle(), $subpage ); |
565 | 565 | } |
— | — | @@ -694,7 +694,7 @@ |
695 | 695 | $watched = false; |
696 | 696 | // Log entries (old format) and special pages |
697 | 697 | } elseif( $rc->mAttribs['rc_namespace'] == NS_SPECIAL ) { |
698 | | - list( $specialName, $logtype ) = SpecialPage::resolveAliasWithSubpage( $rc->mAttribs['rc_title'] ); |
| 698 | + list( $specialName, $logtype ) = SpecialPageFactory::resolveAlias( $rc->mAttribs['rc_title'] ); |
699 | 699 | if ( $specialName == 'Log' ) { |
700 | 700 | # Log updates, etc |
701 | 701 | $logname = LogPage::logName( $logtype ); |
Index: trunk/phase3/includes/Title.php |
— | — | @@ -1812,7 +1812,7 @@ |
1813 | 1813 | # If it's a special page, ditch the subpage bit and check again |
1814 | 1814 | if ( $this->getNamespace() == NS_SPECIAL ) { |
1815 | 1815 | $name = $this->getDBkey(); |
1816 | | - list( $name, /* $subpage */ ) = SpecialPage::resolveAliasWithSubpage( $name ); |
| 1816 | + list( $name, /* $subpage */ ) = SpecialPageFactory::resolveAlias( $name ); |
1817 | 1817 | if ( $name === false ) { |
1818 | 1818 | # Invalid special page, but we show standard login required message |
1819 | 1819 | return false; |
— | — | @@ -3811,7 +3811,7 @@ |
3812 | 3812 | return (bool)wfFindFile( $this ); |
3813 | 3813 | case NS_SPECIAL: |
3814 | 3814 | // valid special page |
3815 | | - return SpecialPage::exists( $this->getDBkey() ); |
| 3815 | + return SpecialPageFactory::exists( $this->getDBkey() ); |
3816 | 3816 | case NS_MAIN: |
3817 | 3817 | // selflink, possibly with fragment |
3818 | 3818 | return $this->mDbkeyform == ''; |
— | — | @@ -4038,7 +4038,7 @@ |
4039 | 4039 | */ |
4040 | 4040 | public function isSpecial( $name ) { |
4041 | 4041 | if ( $this->getNamespace() == NS_SPECIAL ) { |
4042 | | - list( $thisName, /* $subpage */ ) = SpecialPage::resolveAliasWithSubpage( $this->getDBkey() ); |
| 4042 | + list( $thisName, /* $subpage */ ) = SpecialPageFactory::resolveAlias( $this->getDBkey() ); |
4043 | 4043 | if ( $name == $thisName ) { |
4044 | 4044 | return true; |
4045 | 4045 | } |
— | — | @@ -4054,9 +4054,9 @@ |
4055 | 4055 | */ |
4056 | 4056 | public function fixSpecialName() { |
4057 | 4057 | if ( $this->getNamespace() == NS_SPECIAL ) { |
4058 | | - $canonicalName = SpecialPage::resolveAlias( $this->mDbkeyform ); |
| 4058 | + list( $canonicalName, /*...*/ ) = SpecialPageFactory::resolveAlias( $this->mDbkeyform ); |
4059 | 4059 | if ( $canonicalName ) { |
4060 | | - $localName = SpecialPage::getLocalNameFor( $canonicalName ); |
| 4060 | + $localName = SpecialPageFactory::getLocalNameFor( $canonicalName ); |
4061 | 4061 | if ( $localName != $this->mDbkeyform ) { |
4062 | 4062 | return Title::makeTitle( NS_SPECIAL, $localName ); |
4063 | 4063 | } |
Index: trunk/phase3/includes/SkinLegacy.php |
— | — | @@ -432,7 +432,7 @@ |
433 | 433 | function specialPagesList() { |
434 | 434 | global $wgContLang, $wgServer, $wgRedirectScript; |
435 | 435 | |
436 | | - $pages = SpecialPage::getUsablePages(); |
| 436 | + $pages = SpecialPageFactory::getUsablePages(); |
437 | 437 | |
438 | 438 | foreach ( $pages as $name => $page ) { |
439 | 439 | $pages[$name] = $page->getDescription(); |
Index: trunk/phase3/includes/SkinTemplate.php |
— | — | @@ -608,8 +608,7 @@ |
609 | 609 | # contain the original alias-with-subpage. |
610 | 610 | $origTitle = Title::newFromText( $wgRequest->getText( 'title' ) ); |
611 | 611 | if( $origTitle instanceof Title && $origTitle->getNamespace() == NS_SPECIAL ) { |
612 | | - list( $spName, $spPar ) = |
613 | | - SpecialPage::resolveAliasWithSubpage( $origTitle->getText() ); |
| 612 | + list( $spName, $spPar ) = SpecialPageFactory::resolveAlias( $origTitle->getText() ); |
614 | 613 | $active = $spName == 'Contributions' |
615 | 614 | && ( ( $spPar && $spPar == $this->username ) |
616 | 615 | || $wgRequest->getText( 'target' ) == $this->username ); |
Index: trunk/phase3/includes/specials/SpecialSpecialpages.php |
— | — | @@ -51,7 +51,7 @@ |
52 | 52 | private function getPageGroups() { |
53 | 53 | global $wgSortSpecialPages; |
54 | 54 | |
55 | | - $pages = SpecialPage::getUsablePages(); |
| 55 | + $pages = SpecialPageFactory::getUsablePages(); |
56 | 56 | |
57 | 57 | if( !count( $pages ) ) { |
58 | 58 | # Yeah, that was pointless. Thanks for coming. |
— | — | @@ -62,7 +62,7 @@ |
63 | 63 | $groups = array(); |
64 | 64 | foreach ( $pages as $page ) { |
65 | 65 | if ( $page->isListed() ) { |
66 | | - $group = SpecialPage::getGroup( $page ); |
| 66 | + $group = SpecialPageFactory::getGroup( $page ); |
67 | 67 | if( !isset( $groups[$group] ) ) { |
68 | 68 | $groups[$group] = array(); |
69 | 69 | } |
Index: trunk/phase3/includes/Skin.php |
— | — | @@ -303,6 +303,7 @@ |
304 | 304 | * Special:Contributions mark the user which they are relevant to so that |
305 | 305 | * things like the toolbox can display the information they usually are only |
306 | 306 | * able to display on a user's userpage and talkpage. |
| 307 | + * @return User |
307 | 308 | */ |
308 | 309 | public function getRelevantUser() { |
309 | 310 | if ( isset($this->mRelevantUser) ) { |
— | — | @@ -485,7 +486,7 @@ |
486 | 487 | if ( $title->getNamespace() == NS_SPECIAL ) { |
487 | 488 | $type = 'ns-special'; |
488 | 489 | // bug 23315: provide a class based on the canonical special page name without subpages |
489 | | - list( $canonicalName ) = SpecialPage::resolveAliasWithSubpage( $title->getDBkey() ); |
| 490 | + list( $canonicalName ) = SpecialPageFactory::resolveAlias( $title->getDBkey() ); |
490 | 491 | if ( $canonicalName ) { |
491 | 492 | $type .= ' ' . Sanitizer::escapeClass( "mw-special-$canonicalName" ); |
492 | 493 | } else { |
— | — | @@ -1128,7 +1129,7 @@ |
1129 | 1130 | } |
1130 | 1131 | |
1131 | 1132 | static function makeSpecialUrl( $name, $urlaction = '' ) { |
1132 | | - $title = SpecialPage::getTitleFor( $name ); |
| 1133 | + $title = SpecialPage::getSafeTitleFor( $name ); |
1133 | 1134 | return $title->getLocalURL( $urlaction ); |
1134 | 1135 | } |
1135 | 1136 | |
Index: trunk/phase3/includes/SpecialPage.php |
— | — | @@ -201,64 +201,20 @@ |
202 | 202 | static public $mAliases; |
203 | 203 | static public $mListInitialised = false; |
204 | 204 | |
205 | | - /**#@-*/ |
206 | | - |
207 | 205 | /** |
208 | 206 | * Initialise the special page list |
209 | 207 | * This must be called before accessing SpecialPage::$mList |
| 208 | + * @deprecated since 1.18 |
210 | 209 | */ |
211 | 210 | static function initList() { |
212 | | - global $wgSpecialPages; |
213 | | - global $wgDisableCounters, $wgDisableInternalSearch, $wgEmailAuthentication; |
214 | | - |
215 | | - if ( self::$mListInitialised ) { |
216 | | - return; |
217 | | - } |
218 | | - wfProfileIn( __METHOD__ ); |
219 | | - |
220 | | - # Better to set this now, to avoid infinite recursion in carelessly written hooks |
221 | | - self::$mListInitialised = true; |
222 | | - |
223 | | - if( !$wgDisableCounters ) { |
224 | | - self::$mList['Popularpages'] = 'PopularpagesPage'; |
225 | | - } |
226 | | - |
227 | | - if( !$wgDisableInternalSearch ) { |
228 | | - self::$mList['Search'] = 'SpecialSearch'; |
229 | | - } |
230 | | - |
231 | | - if( $wgEmailAuthentication ) { |
232 | | - self::$mList['Confirmemail'] = 'EmailConfirmation'; |
233 | | - self::$mList['Invalidateemail'] = 'EmailInvalidation'; |
234 | | - } |
235 | | - |
236 | | - # Add extension special pages |
237 | | - self::$mList = array_merge( self::$mList, $wgSpecialPages ); |
238 | | - |
239 | | - # Run hooks |
240 | | - # This hook can be used to remove undesired built-in special pages |
241 | | - wfRunHooks( 'SpecialPage_initList', array( &self::$mList ) ); |
242 | | - wfProfileOut( __METHOD__ ); |
| 211 | + // Noop |
243 | 212 | } |
244 | 213 | |
| 214 | + /** |
| 215 | + * @deprecated since 1.18 |
| 216 | + */ |
245 | 217 | static function initAliasList() { |
246 | | - if ( !is_null( self::$mAliases ) ) { |
247 | | - return; |
248 | | - } |
249 | | - |
250 | | - global $wgContLang; |
251 | | - $aliases = $wgContLang->getSpecialPageAliases(); |
252 | | - $missingPages = self::$mList; |
253 | | - self::$mAliases = array(); |
254 | | - foreach ( $aliases as $realName => $aliasList ) { |
255 | | - foreach ( $aliasList as $alias ) { |
256 | | - self::$mAliases[$wgContLang->caseFold( $alias )] = $realName; |
257 | | - } |
258 | | - unset( $missingPages[$realName] ); |
259 | | - } |
260 | | - foreach ( $missingPages as $name => $stuff ) { |
261 | | - self::$mAliases[$wgContLang->caseFold( $name )] = $name; |
262 | | - } |
| 218 | + // Noop |
263 | 219 | } |
264 | 220 | |
265 | 221 | /** |
— | — | @@ -267,19 +223,11 @@ |
268 | 224 | * |
269 | 225 | * @param $alias String |
270 | 226 | * @return String or false |
| 227 | + * @deprecated since 1.18 call SpecialPageFactory method directly |
271 | 228 | */ |
272 | 229 | static function resolveAlias( $alias ) { |
273 | | - global $wgContLang; |
274 | | - |
275 | | - if ( !self::$mListInitialised ) self::initList(); |
276 | | - if ( is_null( self::$mAliases ) ) self::initAliasList(); |
277 | | - $caseFoldedAlias = $wgContLang->caseFold( $alias ); |
278 | | - $caseFoldedAlias = str_replace( ' ', '_', $caseFoldedAlias ); |
279 | | - if ( isset( self::$mAliases[$caseFoldedAlias] ) ) { |
280 | | - return self::$mAliases[$caseFoldedAlias]; |
281 | | - } else { |
282 | | - return false; |
283 | | - } |
| 230 | + list( $name, /*...*/ ) = SpecialPageFactory::resolveAlias( $alias ); |
| 231 | + return $name; |
284 | 232 | } |
285 | 233 | |
286 | 234 | /** |
— | — | @@ -289,16 +237,10 @@ |
290 | 238 | * |
291 | 239 | * @param $alias String |
292 | 240 | * @return Array |
| 241 | + * @deprecated since 1.18 call SpecialPageFactory method directly |
293 | 242 | */ |
294 | 243 | static function resolveAliasWithSubpage( $alias ) { |
295 | | - $bits = explode( '/', $alias, 2 ); |
296 | | - $name = self::resolveAlias( $bits[0] ); |
297 | | - if( !isset( $bits[1] ) ) { // bug 2087 |
298 | | - $par = null; |
299 | | - } else { |
300 | | - $par = $bits[1]; |
301 | | - } |
302 | | - return array( $name, $par ); |
| 244 | + return SpecialPageFactory::resolveAlias( $alias ); |
303 | 245 | } |
304 | 246 | |
305 | 247 | /** |
— | — | @@ -307,14 +249,11 @@ |
308 | 250 | * an associative record to $wgSpecialPages. This avoids autoloading SpecialPage. |
309 | 251 | * |
310 | 252 | * @param $page SpecialPage |
311 | | - * Deprecated in 1.7, warnings in 1.17, might be removed in 1.20 |
| 253 | + * @deprecated in 1.7, warnings in 1.17, might be removed in 1.20 |
312 | 254 | */ |
313 | 255 | static function addPage( &$page ) { |
314 | 256 | wfDeprecated( __METHOD__ ); |
315 | | - if ( !self::$mListInitialised ) { |
316 | | - self::initList(); |
317 | | - } |
318 | | - self::$mList[$page->mName] = $page; |
| 257 | + SpecialPageFactory::getList()->{$page->mName} = $page; |
319 | 258 | } |
320 | 259 | |
321 | 260 | /** |
— | — | @@ -322,47 +261,30 @@ |
323 | 262 | * |
324 | 263 | * @param $page Mixed: SpecialPage or string |
325 | 264 | * @param $group String |
| 265 | + * @deprecated since 1.18 call SpecialPageFactory method directly |
326 | 266 | */ |
327 | 267 | static function setGroup( $page, $group ) { |
328 | | - global $wgSpecialPageGroups; |
329 | | - $name = is_object($page) ? $page->mName : $page; |
330 | | - $wgSpecialPageGroups[$name] = $group; |
| 268 | + return SpecialPageFactory::setGroup( $page, $group ); |
331 | 269 | } |
332 | 270 | |
333 | 271 | /** |
334 | 272 | * Add a page to a certain display group for Special:SpecialPages |
335 | 273 | * |
336 | 274 | * @param $page SpecialPage |
| 275 | + * @deprecated since 1.18 call SpecialPageFactory method directly |
337 | 276 | */ |
338 | 277 | static function getGroup( &$page ) { |
339 | | - global $wgSpecialPageGroups; |
340 | | - static $specialPageGroupsCache = array(); |
341 | | - if( isset($specialPageGroupsCache[$page->mName]) ) { |
342 | | - return $specialPageGroupsCache[$page->mName]; |
343 | | - } |
344 | | - $msg = wfMessage('specialpages-specialpagegroup-'.strtolower($page->mName)); |
345 | | - if ( !$msg->isBlank() ) { |
346 | | - $group = $msg->text(); |
347 | | - } else { |
348 | | - $group = isset($wgSpecialPageGroups[$page->mName]) |
349 | | - ? $wgSpecialPageGroups[$page->mName] |
350 | | - : '-'; |
351 | | - } |
352 | | - if( $group == '-' ) $group = 'other'; |
353 | | - $specialPageGroupsCache[$page->mName] = $group; |
354 | | - return $group; |
| 278 | + return SpecialPageFactory::getGroup( $page ); |
355 | 279 | } |
356 | 280 | |
357 | 281 | /** |
358 | 282 | * Remove a special page from the list |
359 | 283 | * Formerly used to disable expensive or dangerous special pages. The |
360 | 284 | * preferred method is now to add a SpecialPage_initList hook. |
| 285 | + * @deprecated since 1.18 |
361 | 286 | */ |
362 | 287 | static function removePage( $name ) { |
363 | | - if ( !self::$mListInitialised ) { |
364 | | - self::initList(); |
365 | | - } |
366 | | - unset( self::$mList[$name] ); |
| 288 | + unset( SpecialPageFactory::getList()->$name ); |
367 | 289 | } |
368 | 290 | |
369 | 291 | /** |
— | — | @@ -370,24 +292,10 @@ |
371 | 293 | * |
372 | 294 | * @param $name String: name of a special page |
373 | 295 | * @return Boolean: true if a special page exists with this name |
| 296 | + * @deprecated since 1.18 call SpecialPageFactory method directly |
374 | 297 | */ |
375 | 298 | static function exists( $name ) { |
376 | | - global $wgContLang; |
377 | | - if ( !self::$mListInitialised ) { |
378 | | - self::initList(); |
379 | | - } |
380 | | - if( !self::$mAliases ) { |
381 | | - self::initAliasList(); |
382 | | - } |
383 | | - |
384 | | - # Remove special pages inline parameters: |
385 | | - $bits = explode( '/', $name ); |
386 | | - $name = $wgContLang->caseFold($bits[0]); |
387 | | - |
388 | | - return |
389 | | - array_key_exists( $name, self::$mList ) |
390 | | - or array_key_exists( $name, self::$mAliases ) |
391 | | - ; |
| 299 | + return SpecialPageFactory::exists( $name ); |
392 | 300 | } |
393 | 301 | |
394 | 302 | /** |
— | — | @@ -395,26 +303,10 @@ |
396 | 304 | * |
397 | 305 | * @param $name String |
398 | 306 | * @return SpecialPage object or null if the page doesn't exist |
| 307 | + * @deprecated since 1.18 call SpecialPageFactory method directly |
399 | 308 | */ |
400 | 309 | static function getPage( $name ) { |
401 | | - if ( !self::$mListInitialised ) { |
402 | | - self::initList(); |
403 | | - } |
404 | | - if ( array_key_exists( $name, self::$mList ) ) { |
405 | | - $rec = self::$mList[$name]; |
406 | | - if ( is_string( $rec ) ) { |
407 | | - $className = $rec; |
408 | | - self::$mList[$name] = new $className; |
409 | | - } elseif ( is_array( $rec ) ) { |
410 | | - // @deprecated officially since 1.18, unofficially since forever |
411 | | - wfDebug( "Array syntax for \$wgSpecialPages is deprecated, define a subclass of SpecialPage instead." ); |
412 | | - $className = array_shift( $rec ); |
413 | | - self::$mList[$name] = MWFunction::newObj( $className, $rec ); |
414 | | - } |
415 | | - return self::$mList[$name]; |
416 | | - } else { |
417 | | - return null; |
418 | | - } |
| 310 | + return SpecialPageFactory::getPage( $name ); |
419 | 311 | } |
420 | 312 | |
421 | 313 | /** |
— | — | @@ -422,14 +314,10 @@ |
423 | 315 | * is no such special page. |
424 | 316 | * |
425 | 317 | * @return SpecialPage object or null if the page doesn't exist |
| 318 | + * @deprecated since 1.18 call SpecialPageFactory method directly |
426 | 319 | */ |
427 | 320 | static function getPageByAlias( $alias ) { |
428 | | - $realName = self::resolveAlias( $alias ); |
429 | | - if ( $realName ) { |
430 | | - return self::getPage( $realName ); |
431 | | - } else { |
432 | | - return null; |
433 | | - } |
| 321 | + return SpecialPageFactory::getPage( $alias ); |
434 | 322 | } |
435 | 323 | |
436 | 324 | /** |
— | — | @@ -437,46 +325,20 @@ |
438 | 326 | * for the current user, and everyone. |
439 | 327 | * |
440 | 328 | * @return Associative array mapping page's name to its SpecialPage object |
| 329 | + * @deprecated since 1.18 call SpecialPageFactory method directly |
441 | 330 | */ |
442 | 331 | static function getUsablePages() { |
443 | | - global $wgUser; |
444 | | - if ( !self::$mListInitialised ) { |
445 | | - self::initList(); |
446 | | - } |
447 | | - $pages = array(); |
448 | | - |
449 | | - foreach ( self::$mList as $name => $rec ) { |
450 | | - $page = self::getPage( $name ); |
451 | | - if ( $page->isListed() |
452 | | - && ( |
453 | | - !$page->isRestricted() |
454 | | - || $page->userCanExecute( $wgUser ) |
455 | | - ) |
456 | | - ) { |
457 | | - $pages[$name] = $page; |
458 | | - } |
459 | | - } |
460 | | - return $pages; |
| 332 | + return SpecialPageFactory::getUsablePages(); |
461 | 333 | } |
462 | 334 | |
463 | 335 | /** |
464 | 336 | * Return categorised listable special pages for all users |
465 | 337 | * |
466 | 338 | * @return Associative array mapping page's name to its SpecialPage object |
| 339 | + * @deprecated since 1.18 call SpecialPageFactory method directly |
467 | 340 | */ |
468 | 341 | static function getRegularPages() { |
469 | | - if ( !self::$mListInitialised ) { |
470 | | - self::initList(); |
471 | | - } |
472 | | - $pages = array(); |
473 | | - |
474 | | - foreach ( self::$mList as $name => $rec ) { |
475 | | - $page = self::getPage( $name ); |
476 | | - if ( $page->isListed() && !$page->isRestricted() ) { |
477 | | - $pages[$name] = $page; |
478 | | - } |
479 | | - } |
480 | | - return $pages; |
| 342 | + return SpecialPageFactory::getRegularPages(); |
481 | 343 | } |
482 | 344 | |
483 | 345 | /** |
— | — | @@ -484,25 +346,10 @@ |
485 | 347 | * for the current user, but not for everyone |
486 | 348 | * |
487 | 349 | * @return Associative array mapping page's name to its SpecialPage object |
| 350 | + * @deprecated since 1.18 call SpecialPageFactory method directly |
488 | 351 | */ |
489 | 352 | static function getRestrictedPages() { |
490 | | - global $wgUser; |
491 | | - if( !self::$mListInitialised ) { |
492 | | - self::initList(); |
493 | | - } |
494 | | - $pages = array(); |
495 | | - |
496 | | - foreach( self::$mList as $name => $rec ) { |
497 | | - $page = self::getPage( $name ); |
498 | | - if( |
499 | | - $page->isListed() |
500 | | - && $page->isRestricted() |
501 | | - && $page->userCanExecute( $wgUser ) |
502 | | - ) { |
503 | | - $pages[$name] = $page; |
504 | | - } |
505 | | - } |
506 | | - return $pages; |
| 353 | + return SpecialPageFactory::getRestrictedPages(); |
507 | 354 | } |
508 | 355 | |
509 | 356 | /** |
— | — | @@ -516,81 +363,10 @@ |
517 | 364 | * @param $title Title object |
518 | 365 | * @param $context RequestContext |
519 | 366 | * @param $including Bool output is being captured for use in {{special:whatever}} |
| 367 | + * @deprecated since 1.18 call SpecialPageFactory method directly |
520 | 368 | */ |
521 | 369 | public static function executePath( &$title, RequestContext &$context, $including = false ) { |
522 | | - wfProfileIn( __METHOD__ ); |
523 | | - |
524 | | - # FIXME: redirects broken due to this call |
525 | | - $bits = explode( '/', $title->getDBkey(), 2 ); |
526 | | - $name = $bits[0]; |
527 | | - if( !isset( $bits[1] ) ) { // bug 2087 |
528 | | - $par = null; |
529 | | - } else { |
530 | | - $par = $bits[1]; |
531 | | - } |
532 | | - $page = SpecialPage::getPageByAlias( $name ); |
533 | | - # Nonexistent? |
534 | | - if ( !$page ) { |
535 | | - $context->output->setArticleRelated( false ); |
536 | | - $context->output->setRobotPolicy( 'noindex,nofollow' ); |
537 | | - $context->output->setStatusCode( 404 ); |
538 | | - $context->output->showErrorPage( 'nosuchspecialpage', 'nospecialpagetext' ); |
539 | | - wfProfileOut( __METHOD__ ); |
540 | | - return false; |
541 | | - } |
542 | | - |
543 | | - # Page exists, set the context |
544 | | - $page->setContext( $context ); |
545 | | - |
546 | | - # Check for redirect |
547 | | - if ( !$including ) { |
548 | | - $redirect = $page->getRedirect( $par ); |
549 | | - $query = $page->getRedirectQuery(); |
550 | | - if ( $redirect instanceof Title ) { |
551 | | - $url = $redirect->getFullUrl( $query ); |
552 | | - $context->output->redirect( $url ); |
553 | | - wfProfileOut( __METHOD__ ); |
554 | | - return $redirect; |
555 | | - } elseif( $redirect === true ) { |
556 | | - global $wgScript; |
557 | | - $url = $wgScript . '?' . wfArrayToCGI( $query ); |
558 | | - $context->output->redirect( $url ); |
559 | | - wfProfileOut( __METHOD__ ); |
560 | | - return $redirect; |
561 | | - } |
562 | | - } |
563 | | - |
564 | | - # Redirect to canonical alias for GET commands |
565 | | - # Not for POST, we'd lose the post data, so it's best to just distribute |
566 | | - # the request. Such POST requests are possible for old extensions that |
567 | | - # generate self-links without being aware that their default name has |
568 | | - # changed. |
569 | | - if ( !$including && $name != $page->getLocalName() && !$context->request->wasPosted() ) { |
570 | | - $query = $_GET; |
571 | | - unset( $query['title'] ); |
572 | | - $query = wfArrayToCGI( $query ); |
573 | | - $title = $page->getTitle( $par ); |
574 | | - $url = $title->getFullUrl( $query ); |
575 | | - $context->output->redirect( $url ); |
576 | | - wfProfileOut( __METHOD__ ); |
577 | | - return $redirect; |
578 | | - } |
579 | | - |
580 | | - if ( $including && !$page->includable() ) { |
581 | | - wfProfileOut( __METHOD__ ); |
582 | | - return false; |
583 | | - } elseif ( !$including ) { |
584 | | - $context->title = $page->getTitle(); |
585 | | - } |
586 | | - $page->including( $including ); |
587 | | - |
588 | | - // Execute special page |
589 | | - $profName = 'Special:' . $page->name(); |
590 | | - wfProfileIn( $profName ); |
591 | | - $page->execute( $par ); |
592 | | - wfProfileOut( $profName ); |
593 | | - wfProfileOut( __METHOD__ ); |
594 | | - return true; |
| 370 | + return SpecialPageFactory::executePath( $title, $context, $including ); |
595 | 371 | } |
596 | 372 | |
597 | 373 | /** |
— | — | @@ -599,24 +375,10 @@ |
600 | 376 | * a redirect. |
601 | 377 | * |
602 | 378 | * @return String: HTML fragment |
| 379 | + * @deprecated since 1.18 call SpecialPageFactory method directly |
603 | 380 | */ |
604 | 381 | static function capturePath( &$title ) { |
605 | | - global $wgOut, $wgTitle; |
606 | | - |
607 | | - $oldTitle = $wgTitle; |
608 | | - $oldOut = $wgOut; |
609 | | - |
610 | | - $context = new RequestContext; |
611 | | - $context->setTitle( $title ); |
612 | | - $wgOut = $context->getOutput(); |
613 | | - |
614 | | - $ret = SpecialPage::executePath( $title, $context, true ); |
615 | | - if ( $ret === true ) { |
616 | | - $ret = $wgOut->getHTML(); |
617 | | - } |
618 | | - $wgTitle = $oldTitle; |
619 | | - $wgOut = $oldOut; |
620 | | - return $ret; |
| 382 | + return SpecialPageFactory::capturePath( $title ); |
621 | 383 | } |
622 | 384 | |
623 | 385 | /** |
— | — | @@ -626,33 +388,10 @@ |
627 | 389 | * @param $subpage Mixed: boolean false, or string |
628 | 390 | * |
629 | 391 | * @return String |
| 392 | + * @deprecated since 1.18 call SpecialPageFactory method directly |
630 | 393 | */ |
631 | 394 | static function getLocalNameFor( $name, $subpage = false ) { |
632 | | - global $wgContLang; |
633 | | - $aliases = $wgContLang->getSpecialPageAliases(); |
634 | | - if ( isset( $aliases[$name][0] ) ) { |
635 | | - $name = $aliases[$name][0]; |
636 | | - } else { |
637 | | - // Try harder in case someone misspelled the correct casing |
638 | | - $found = false; |
639 | | - foreach ( $aliases as $n => $values ) { |
640 | | - if ( strcasecmp( $name, $n ) === 0 ) { |
641 | | - wfWarn( "Found alias defined for $n when searching for " . |
642 | | - "special page aliases for $name. Case mismatch?" ); |
643 | | - $name = $values[0]; |
644 | | - $found = true; |
645 | | - break; |
646 | | - } |
647 | | - } |
648 | | - if ( !$found ) { |
649 | | - wfWarn( "Did not find alias for special page '$name'. " . |
650 | | - "Perhaps no aliases are defined for it?" ); |
651 | | - } |
652 | | - } |
653 | | - if ( $subpage !== false && !is_null( $subpage ) ) { |
654 | | - $name = "$name/$subpage"; |
655 | | - } |
656 | | - return $wgContLang->ucfirst( $name ); |
| 395 | + return SpecialPageFactory::getLocalNameFor( $name, $subpage ); |
657 | 396 | } |
658 | 397 | |
659 | 398 | /** |
— | — | @@ -660,8 +399,8 @@ |
661 | 400 | * |
662 | 401 | * @return Title object |
663 | 402 | */ |
664 | | - static function getTitleFor( $name, $subpage = false ) { |
665 | | - $name = self::getLocalNameFor( $name, $subpage ); |
| 403 | + public static function getTitleFor( $name, $subpage = false ) { |
| 404 | + $name = SpecialPageFactory::getLocalNameFor( $name, $subpage ); |
666 | 405 | if ( $name ) { |
667 | 406 | return Title::makeTitle( NS_SPECIAL, $name ); |
668 | 407 | } else { |
— | — | @@ -674,8 +413,8 @@ |
675 | 414 | * |
676 | 415 | * @return Title object or null if the page doesn't exist |
677 | 416 | */ |
678 | | - static function getSafeTitleFor( $name, $subpage = false ) { |
679 | | - $name = self::getLocalNameFor( $name, $subpage ); |
| 417 | + public static function getSafeTitleFor( $name, $subpage = false ) { |
| 418 | + $name = SpecialPageFactory::getLocalNameFor( $name, $subpage ); |
680 | 419 | if ( $name ) { |
681 | 420 | return Title::makeTitleSafe( NS_SPECIAL, $name ); |
682 | 421 | } else { |
— | — | @@ -687,14 +426,10 @@ |
688 | 427 | * Get a title for a given alias |
689 | 428 | * |
690 | 429 | * @return Title or null if there is no such alias |
| 430 | + * @deprecated since 1.18 call SpecialPageFactory method directly |
691 | 431 | */ |
692 | 432 | static function getTitleForAlias( $alias ) { |
693 | | - $name = self::resolveAlias( $alias ); |
694 | | - if ( $name ) { |
695 | | - return self::getTitleFor( $name ); |
696 | | - } else { |
697 | | - return null; |
698 | | - } |
| 433 | + return SpecialPageFactory::getTitleForAlias( $alias ); |
699 | 434 | } |
700 | 435 | |
701 | 436 | /** |
— | — | @@ -800,7 +535,7 @@ |
801 | 536 | */ |
802 | 537 | function getLocalName() { |
803 | 538 | if ( !isset( $this->mLocalName ) ) { |
804 | | - $this->mLocalName = self::getLocalNameFor( $this->mName ); |
| 539 | + $this->mLocalName = SpecialPageFactory::getLocalNameFor( $this->mName ); |
805 | 540 | } |
806 | 541 | return $this->mLocalName; |
807 | 542 | } |
— | — | @@ -846,7 +581,7 @@ |
847 | 582 | * Output an error message telling the user what access level they have to have |
848 | 583 | */ |
849 | 584 | function displayRestrictionError() { |
850 | | - $this->getOutput()->permissionRequired( $this->mRestriction ); |
| 585 | + throw new PermissionsError( $this->mRestriction ); |
851 | 586 | } |
852 | 587 | |
853 | 588 | /** |
— | — | @@ -928,6 +663,8 @@ |
929 | 664 | |
930 | 665 | /** |
931 | 666 | * Set whether this page is listed in Special:Specialpages, at run-time |
| 667 | + * |
| 668 | + * @return Bool |
932 | 669 | */ |
933 | 670 | function setListed( $listed ) { |
934 | 671 | return wfSetVar( $this->mListed, $listed ); |
— | — | @@ -936,6 +673,8 @@ |
937 | 674 | /** |
938 | 675 | * If the special page is a redirect, then get the Title object it redirects to. |
939 | 676 | * False otherwise. |
| 677 | + * |
| 678 | + * @return Title|false |
940 | 679 | */ |
941 | 680 | function getRedirect( $subpage ) { |
942 | 681 | return false; |
— | — | @@ -971,7 +710,7 @@ |
972 | 711 | * @param $context RequestContext |
973 | 712 | * @since 1.18 |
974 | 713 | */ |
975 | | - protected function setContext( $context ) { |
| 714 | + public function setContext( $context ) { |
976 | 715 | $this->mContext = $context; |
977 | 716 | } |
978 | 717 | |
— | — | @@ -1090,9 +829,9 @@ |
1091 | 830 | |
1092 | 831 | function getRedirect( $subpage ) { |
1093 | 832 | if ( $this->redirSubpage === false ) { |
1094 | | - return SpecialPage::getTitleFor( $this->redirName, $subpage ); |
| 833 | + return SpecialPageFactory::getTitleFor( $this->redirName, $subpage ); |
1095 | 834 | } else { |
1096 | | - return SpecialPage::getTitleFor( $this->redirName, $this->redirSubpage ); |
| 835 | + return SpecialPageFactory::getTitleFor( $this->redirName, $this->redirSubpage ); |
1097 | 836 | } |
1098 | 837 | } |
1099 | 838 | } |
— | — | @@ -1187,7 +926,7 @@ |
1188 | 927 | |
1189 | 928 | function getRedirect( $subpage ) { |
1190 | 929 | global $wgUser; |
1191 | | - return SpecialPage::getTitleFor( 'Contributions', $wgUser->getName() ); |
| 930 | + return SpecialPageFactory::getTitleFor( 'Contributions', $wgUser->getName() ); |
1192 | 931 | } |
1193 | 932 | } |
1194 | 933 | |
— | — | @@ -1202,7 +941,7 @@ |
1203 | 942 | |
1204 | 943 | function getRedirect( $subpage ) { |
1205 | 944 | global $wgUser; |
1206 | | - return SpecialPage::getTitleFor( 'Listfiles', $wgUser->getName() ); |
| 945 | + return SpecialPageFactory::getTitleFor( 'Listfiles', $wgUser->getName() ); |
1207 | 946 | } |
1208 | 947 | } |
1209 | 948 | |