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