MediaWiki
REL1_24
|
00001 <?php 00032 class SpecialPage { 00033 // The canonical name of this special page 00034 // Also used for the default <h1> heading, @see getDescription() 00035 protected $mName; 00036 00037 // The local name of this special page 00038 private $mLocalName; 00039 00040 // Minimum user level required to access this page, or "" for anyone. 00041 // Also used to categorise the pages in Special:Specialpages 00042 protected $mRestriction; 00043 00044 // Listed in Special:Specialpages? 00045 private $mListed; 00046 00047 // Whether or not this special page is being included from an article 00048 protected $mIncluding; 00049 00050 // Whether the special page can be included in an article 00051 protected $mIncludable; 00052 00057 protected $mContext; 00058 00068 public static function getTitleFor( $name, $subpage = false, $fragment = '' ) { 00069 $name = SpecialPageFactory::getLocalNameFor( $name, $subpage ); 00070 00071 return Title::makeTitle( NS_SPECIAL, $name, $fragment ); 00072 } 00073 00081 public static function getSafeTitleFor( $name, $subpage = false ) { 00082 $name = SpecialPageFactory::getLocalNameFor( $name, $subpage ); 00083 if ( $name ) { 00084 return Title::makeTitleSafe( NS_SPECIAL, $name ); 00085 } else { 00086 return null; 00087 } 00088 } 00089 00107 public function __construct( 00108 $name = '', $restriction = '', $listed = true, 00109 $function = false, $file = '', $includable = false 00110 ) { 00111 $this->mName = $name; 00112 $this->mRestriction = $restriction; 00113 $this->mListed = $listed; 00114 $this->mIncludable = $includable; 00115 } 00116 00121 function getName() { 00122 return $this->mName; 00123 } 00124 00129 function getRestriction() { 00130 return $this->mRestriction; 00131 } 00132 00133 // @todo FIXME: Decide which syntax to use for this, and stick to it 00139 function isListed() { 00140 return $this->mListed; 00141 } 00142 00149 function setListed( $listed ) { 00150 return wfSetVar( $this->mListed, $listed ); 00151 } 00152 00159 function listed( $x = null ) { 00160 return wfSetVar( $this->mListed, $x ); 00161 } 00162 00167 public function isIncludable() { 00168 return $this->mIncludable; 00169 } 00170 00176 function including( $x = null ) { 00177 return wfSetVar( $this->mIncluding, $x ); 00178 } 00179 00184 function getLocalName() { 00185 if ( !isset( $this->mLocalName ) ) { 00186 $this->mLocalName = SpecialPageFactory::getLocalNameFor( $this->mName ); 00187 } 00188 00189 return $this->mLocalName; 00190 } 00191 00200 public function isExpensive() { 00201 return false; 00202 } 00203 00213 public function isCached() { 00214 return false; 00215 } 00216 00224 public function isRestricted() { 00225 // DWIM: If anons can do something, then it is not restricted 00226 return $this->mRestriction != '' && !User::groupHasPermission( '*', $this->mRestriction ); 00227 } 00228 00237 public function userCanExecute( User $user ) { 00238 return $user->isAllowed( $this->mRestriction ); 00239 } 00240 00245 function displayRestrictionError() { 00246 throw new PermissionsError( $this->mRestriction ); 00247 } 00248 00256 public function checkPermissions() { 00257 if ( !$this->userCanExecute( $this->getUser() ) ) { 00258 $this->displayRestrictionError(); 00259 } 00260 } 00261 00269 public function checkReadOnly() { 00270 if ( wfReadOnly() ) { 00271 throw new ReadOnlyError; 00272 } 00273 } 00274 00286 public function requireLogin( 00287 $reasonMsg = 'exception-nologin-text', $titleMsg = 'exception-nologin' 00288 ) { 00289 if ( $this->getUser()->isAnon() ) { 00290 throw new UserNotLoggedIn( $reasonMsg, $titleMsg ); 00291 } 00292 } 00293 00309 public function prefixSearchSubpages( $search, $limit = 10 ) { 00310 return array(); 00311 } 00312 00323 protected static function prefixSearchArray( $search, $limit, array $subpages ) { 00324 $escaped = preg_quote( $search, '/' ); 00325 return array_slice( preg_grep( "/^$escaped/i", $subpages ), 0, $limit ); 00326 } 00327 00331 function setHeaders() { 00332 $out = $this->getOutput(); 00333 $out->setArticleRelated( false ); 00334 $out->setRobotPolicy( $this->getRobotPolicy() ); 00335 $out->setPageTitle( $this->getDescription() ); 00336 if ( $this->getConfig()->get( 'UseMediaWikiUIEverywhere' ) ) { 00337 $out->addModuleStyles( array( 00338 'mediawiki.ui.input', 00339 'mediawiki.ui.checkbox', 00340 ) ); 00341 } 00342 } 00343 00351 final public function run( $subPage ) { 00360 wfRunHooks( 'SpecialPageBeforeExecute', array( $this, $subPage ) ); 00361 00362 $this->beforeExecute( $subPage ); 00363 $this->execute( $subPage ); 00364 $this->afterExecute( $subPage ); 00365 00374 wfRunHooks( 'SpecialPageAfterExecute', array( $this, $subPage ) ); 00375 } 00376 00384 protected function beforeExecute( $subPage ) { 00385 // No-op 00386 } 00387 00395 protected function afterExecute( $subPage ) { 00396 // No-op 00397 } 00398 00407 public function execute( $subPage ) { 00408 $this->setHeaders(); 00409 $this->checkPermissions(); 00410 $this->outputHeader(); 00411 } 00412 00421 function outputHeader( $summaryMessageKey = '' ) { 00422 global $wgContLang; 00423 00424 if ( $summaryMessageKey == '' ) { 00425 $msg = $wgContLang->lc( $this->getName() ) . '-summary'; 00426 } else { 00427 $msg = $summaryMessageKey; 00428 } 00429 if ( !$this->msg( $msg )->isDisabled() && !$this->including() ) { 00430 $this->getOutput()->wrapWikiMsg( 00431 "<div class='mw-specialpage-summary'>\n$1\n</div>", $msg ); 00432 } 00433 } 00434 00444 function getDescription() { 00445 return $this->msg( strtolower( $this->mName ) )->text(); 00446 } 00447 00455 function getTitle( $subpage = false ) { 00456 return $this->getPageTitle( $subpage ); 00457 } 00458 00466 function getPageTitle( $subpage = false ) { 00467 return self::getTitleFor( $this->mName, $subpage ); 00468 } 00469 00476 public function setContext( $context ) { 00477 $this->mContext = $context; 00478 } 00479 00486 public function getContext() { 00487 if ( $this->mContext instanceof IContextSource ) { 00488 return $this->mContext; 00489 } else { 00490 wfDebug( __METHOD__ . " called and \$mContext is null. " . 00491 "Return RequestContext::getMain(); for sanity\n" ); 00492 00493 return RequestContext::getMain(); 00494 } 00495 } 00496 00503 public function getRequest() { 00504 return $this->getContext()->getRequest(); 00505 } 00506 00513 public function getOutput() { 00514 return $this->getContext()->getOutput(); 00515 } 00516 00523 public function getUser() { 00524 return $this->getContext()->getUser(); 00525 } 00526 00533 public function getSkin() { 00534 return $this->getContext()->getSkin(); 00535 } 00536 00543 public function getLanguage() { 00544 return $this->getContext()->getLanguage(); 00545 } 00546 00552 public function getConfig() { 00553 return $this->getContext()->getConfig(); 00554 } 00555 00562 public function getFullTitle() { 00563 return $this->getContext()->getTitle(); 00564 } 00565 00573 protected function getRobotPolicy() { 00574 return 'noindex,nofollow'; 00575 } 00576 00583 public function msg( /* $args */ ) { 00584 $message = call_user_func_array( 00585 array( $this->getContext(), 'msg' ), 00586 func_get_args() 00587 ); 00588 // RequestContext passes context to wfMessage, and the language is set from 00589 // the context, but setting the language for Message class removes the 00590 // interface message status, which breaks for example usernameless gender 00591 // invocations. Restore the flag when not including special page in content. 00592 if ( $this->including() ) { 00593 $message->setInterfaceMessageFlag( false ); 00594 } 00595 00596 return $message; 00597 } 00598 00604 protected function addFeedLinks( $params ) { 00605 $feedTemplate = wfScript( 'api' ); 00606 00607 foreach ( $this->getConfig()->get( 'FeedClasses' ) as $format => $class ) { 00608 $theseParams = $params + array( 'feedformat' => $format ); 00609 $url = wfAppendQuery( $feedTemplate, $theseParams ); 00610 $this->getOutput()->addFeedLink( $format, $url ); 00611 } 00612 } 00613 00622 public function getFinalGroupName() { 00623 $name = $this->getName(); 00624 $specialPageGroups = $this->getConfig()->get( 'SpecialPageGroups' ); 00625 00626 // Allow overbidding the group from the wiki side 00627 $msg = $this->msg( 'specialpages-specialpagegroup-' . strtolower( $name ) )->inContentLanguage(); 00628 if ( !$msg->isBlank() ) { 00629 $group = $msg->text(); 00630 } else { 00631 // Than use the group from this object 00632 $group = $this->getGroupName(); 00633 00634 // Group '-' is used as default to have the chance to determine, 00635 // if the special pages overrides this method, 00636 // if not overridden, $wgSpecialPageGroups is checked for b/c 00637 if ( $group === '-' && isset( $specialPageGroups[$name] ) ) { 00638 $group = $specialPageGroups[$name]; 00639 } 00640 } 00641 00642 // never give '-' back, change to 'other' 00643 if ( $group === '-' ) { 00644 $group = 'other'; 00645 } 00646 00647 return $group; 00648 } 00649 00658 protected function getGroupName() { 00659 // '-' used here to determine, if this group is overridden or has a hardcoded 'other' 00660 // Needed for b/c in getFinalGroupName 00661 return '-'; 00662 } 00663 }