MediaWiki  REL1_23
SpecialPage.php
Go to the documentation of this file.
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 }