MediaWiki
REL1_23
|
00001 <?php 00033 class SpecialPage { 00034 // The canonical name of this special page 00035 // Also used for the default <h1> heading, @see getDescription() 00036 protected $mName; 00037 00038 // The local name of this special page 00039 private $mLocalName; 00040 00041 // Minimum user level required to access this page, or "" for anyone. 00042 // Also used to categorise the pages in Special:Specialpages 00043 private $mRestriction; 00044 00045 // Listed in Special:Specialpages? 00046 private $mListed; 00047 00048 // Function name called by the default execute() 00049 private $mFunction; 00050 00051 // File which needs to be included before the function above can be called 00052 private $mFile; 00053 00054 // Whether or not this special page is being included from an article 00055 protected $mIncluding; 00056 00057 // Whether the special page can be included in an article 00058 protected $mIncludable; 00059 00064 protected $mContext; 00065 00075 public static function getTitleFor( $name, $subpage = false, $fragment = '' ) { 00076 $name = SpecialPageFactory::getLocalNameFor( $name, $subpage ); 00077 00078 return Title::makeTitle( NS_SPECIAL, $name, $fragment ); 00079 } 00080 00088 public static function getSafeTitleFor( $name, $subpage = false ) { 00089 $name = SpecialPageFactory::getLocalNameFor( $name, $subpage ); 00090 if ( $name ) { 00091 return Title::makeTitleSafe( NS_SPECIAL, $name ); 00092 } else { 00093 return null; 00094 } 00095 } 00096 00116 public function __construct( 00117 $name = '', $restriction = '', $listed = true, 00118 $function = false, $file = 'default', $includable = false 00119 ) { 00120 $this->mName = $name; 00121 $this->mRestriction = $restriction; 00122 $this->mListed = $listed; 00123 $this->mIncludable = $includable; 00124 if ( !$function ) { 00125 $this->mFunction = 'wfSpecial' . $name; 00126 } else { 00127 $this->mFunction = $function; 00128 } 00129 if ( $file === 'default' ) { 00130 $this->mFile = __DIR__ . "/specials/Special$name.php"; 00131 } else { 00132 $this->mFile = $file; 00133 } 00134 } 00135 00140 function getName() { 00141 return $this->mName; 00142 } 00143 00148 function getRestriction() { 00149 return $this->mRestriction; 00150 } 00151 00159 function getFile() { 00160 wfDeprecated( __METHOD__, '1.18' ); 00161 00162 return $this->mFile; 00163 } 00164 00165 // @todo FIXME: Decide which syntax to use for this, and stick to it 00171 function isListed() { 00172 return $this->mListed; 00173 } 00174 00181 function setListed( $listed ) { 00182 return wfSetVar( $this->mListed, $listed ); 00183 } 00184 00191 function listed( $x = null ) { 00192 return wfSetVar( $this->mListed, $x ); 00193 } 00194 00199 public function isIncludable() { 00200 return $this->mIncludable; 00201 } 00202 00208 function including( $x = null ) { 00209 return wfSetVar( $this->mIncluding, $x ); 00210 } 00211 00216 function getLocalName() { 00217 if ( !isset( $this->mLocalName ) ) { 00218 $this->mLocalName = SpecialPageFactory::getLocalNameFor( $this->mName ); 00219 } 00220 00221 return $this->mLocalName; 00222 } 00223 00232 public function isExpensive() { 00233 return false; 00234 } 00235 00245 public function isCached() { 00246 return false; 00247 } 00248 00256 public function isRestricted() { 00257 // DWIM: If anons can do something, then it is not restricted 00258 return $this->mRestriction != '' && !User::groupHasPermission( '*', $this->mRestriction ); 00259 } 00260 00269 public function userCanExecute( User $user ) { 00270 return $user->isAllowed( $this->mRestriction ); 00271 } 00272 00277 function displayRestrictionError() { 00278 throw new PermissionsError( $this->mRestriction ); 00279 } 00280 00288 public function checkPermissions() { 00289 if ( !$this->userCanExecute( $this->getUser() ) ) { 00290 $this->displayRestrictionError(); 00291 } 00292 } 00293 00301 public function checkReadOnly() { 00302 if ( wfReadOnly() ) { 00303 throw new ReadOnlyError; 00304 } 00305 } 00306 00322 public function requireLogin( $reasonMsg = null, $titleMsg = null ) { 00323 if ( $this->getUser()->isAnon() ) { 00324 // Use default messages if not given or explicit null passed 00325 if ( !$reasonMsg ) { 00326 $reasonMsg = 'exception-nologin-text-manual'; 00327 } 00328 if ( !$titleMsg ) { 00329 $titleMsg = 'exception-nologin'; 00330 } 00331 00332 // Convert to Messages with current context 00333 if ( is_string( $reasonMsg ) ) { 00334 $loginreqlink = Linker::linkKnown( 00335 SpecialPage::getTitleFor( 'Userlogin' ), 00336 $this->msg( 'loginreqlink' )->escaped(), 00337 array(), 00338 array( 'returnto' => $this->getPageTitle()->getPrefixedText() ) 00339 ); 00340 $reasonMsg = $this->msg( $reasonMsg )->rawParams( $loginreqlink ); 00341 } 00342 if ( is_string( $titleMsg ) ) { 00343 $titleMsg = $this->msg( $titleMsg ); 00344 } 00345 00346 throw new UserNotLoggedIn( $reasonMsg, $titleMsg ); 00347 } 00348 } 00349 00353 function setHeaders() { 00354 $out = $this->getOutput(); 00355 $out->setArticleRelated( false ); 00356 $out->setRobotPolicy( $this->getRobotPolicy() ); 00357 $out->setPageTitle( $this->getDescription() ); 00358 } 00359 00367 final public function run( $subPage ) { 00376 wfRunHooks( 'SpecialPageBeforeExecute', array( $this, $subPage ) ); 00377 00378 $this->beforeExecute( $subPage ); 00379 $this->execute( $subPage ); 00380 $this->afterExecute( $subPage ); 00381 00390 wfRunHooks( 'SpecialPageAfterExecute', array( $this, $subPage ) ); 00391 } 00392 00400 protected function beforeExecute( $subPage ) { 00401 // No-op 00402 } 00403 00411 protected function afterExecute( $subPage ) { 00412 // No-op 00413 } 00414 00423 public function execute( $subPage ) { 00424 $this->setHeaders(); 00425 $this->checkPermissions(); 00426 00427 $func = $this->mFunction; 00428 // only load file if the function does not exist 00429 if ( !is_callable( $func ) && $this->mFile ) { 00430 require_once $this->mFile; 00431 } 00432 $this->outputHeader(); 00433 call_user_func( $func, $subPage, $this ); 00434 } 00435 00444 function outputHeader( $summaryMessageKey = '' ) { 00445 global $wgContLang; 00446 00447 if ( $summaryMessageKey == '' ) { 00448 $msg = $wgContLang->lc( $this->getName() ) . '-summary'; 00449 } else { 00450 $msg = $summaryMessageKey; 00451 } 00452 if ( !$this->msg( $msg )->isDisabled() && !$this->including() ) { 00453 $this->getOutput()->wrapWikiMsg( 00454 "<div class='mw-specialpage-summary'>\n$1\n</div>", $msg ); 00455 } 00456 } 00457 00467 function getDescription() { 00468 return $this->msg( strtolower( $this->mName ) )->text(); 00469 } 00470 00478 function getTitle( $subpage = false ) { 00479 return $this->getPageTitle( $subpage ); 00480 } 00481 00489 function getPageTitle( $subpage = false ) { 00490 return self::getTitleFor( $this->mName, $subpage ); 00491 } 00492 00499 public function setContext( $context ) { 00500 $this->mContext = $context; 00501 } 00502 00509 public function getContext() { 00510 if ( $this->mContext instanceof IContextSource ) { 00511 return $this->mContext; 00512 } else { 00513 wfDebug( __METHOD__ . " called and \$mContext is null. " . 00514 "Return RequestContext::getMain(); for sanity\n" ); 00515 00516 return RequestContext::getMain(); 00517 } 00518 } 00519 00526 public function getRequest() { 00527 return $this->getContext()->getRequest(); 00528 } 00529 00536 public function getOutput() { 00537 return $this->getContext()->getOutput(); 00538 } 00539 00546 public function getUser() { 00547 return $this->getContext()->getUser(); 00548 } 00549 00556 public function getSkin() { 00557 return $this->getContext()->getSkin(); 00558 } 00559 00567 public function getLang() { 00568 wfDeprecated( __METHOD__, '1.19' ); 00569 00570 return $this->getLanguage(); 00571 } 00572 00579 public function getLanguage() { 00580 return $this->getContext()->getLanguage(); 00581 } 00582 00589 public function getFullTitle() { 00590 return $this->getContext()->getTitle(); 00591 } 00592 00600 protected function getRobotPolicy() { 00601 return 'noindex,nofollow'; 00602 } 00603 00610 public function msg( /* $args */ ) { 00611 $message = call_user_func_array( 00612 array( $this->getContext(), 'msg' ), 00613 func_get_args() 00614 ); 00615 // RequestContext passes context to wfMessage, and the language is set from 00616 // the context, but setting the language for Message class removes the 00617 // interface message status, which breaks for example usernameless gender 00618 // invocations. Restore the flag when not including special page in content. 00619 if ( $this->including() ) { 00620 $message->setInterfaceMessageFlag( false ); 00621 } 00622 00623 return $message; 00624 } 00625 00631 protected function addFeedLinks( $params ) { 00632 global $wgFeedClasses; 00633 00634 $feedTemplate = wfScript( 'api' ); 00635 00636 foreach ( $wgFeedClasses as $format => $class ) { 00637 $theseParams = $params + array( 'feedformat' => $format ); 00638 $url = wfAppendQuery( $feedTemplate, $theseParams ); 00639 $this->getOutput()->addFeedLink( $format, $url ); 00640 } 00641 } 00642 00651 public function getFinalGroupName() { 00652 global $wgSpecialPageGroups; 00653 $name = $this->getName(); 00654 00655 // Allow overbidding the group from the wiki side 00656 $msg = $this->msg( 'specialpages-specialpagegroup-' . strtolower( $name ) )->inContentLanguage(); 00657 if ( !$msg->isBlank() ) { 00658 $group = $msg->text(); 00659 } else { 00660 // Than use the group from this object 00661 $group = $this->getGroupName(); 00662 00663 // Group '-' is used as default to have the chance to determine, 00664 // if the special pages overrides this method, 00665 // if not overridden, $wgSpecialPageGroups is checked for b/c 00666 if ( $group === '-' && isset( $wgSpecialPageGroups[$name] ) ) { 00667 $group = $wgSpecialPageGroups[$name]; 00668 } 00669 } 00670 00671 // never give '-' back, change to 'other' 00672 if ( $group === '-' ) { 00673 $group = 'other'; 00674 } 00675 00676 return $group; 00677 } 00678 00687 protected function getGroupName() { 00688 // '-' used here to determine, if this group is overridden or has a hardcoded 'other' 00689 // Needed for b/c in getFinalGroupName 00690 return '-'; 00691 } 00692 }