diff options
Diffstat (limited to 'includes/SpecialPage.php')
-rw-r--r-- | includes/SpecialPage.php | 307 |
1 files changed, 220 insertions, 87 deletions
diff --git a/includes/SpecialPage.php b/includes/SpecialPage.php index 2e5e02b0..a6195fc4 100644 --- a/includes/SpecialPage.php +++ b/includes/SpecialPage.php @@ -27,7 +27,6 @@ * @ingroup SpecialPage */ class SpecialPage { - // The canonical name of this special page // Also used for the default <h1> heading, @see getDescription() protected $mName; @@ -106,19 +105,6 @@ class SpecialPage { } /** - * Add a page to the list of valid special pages. This used to be the preferred - * method for adding special pages in extensions. It's now suggested that you add - * an associative record to $wgSpecialPages. This avoids autoloading SpecialPage. - * - * @param $page SpecialPage - * @deprecated since 1.7, warnings in 1.17, might be removed in 1.20 - */ - static function addPage( &$page ) { - wfDeprecated( __METHOD__, '1.7' ); - SpecialPageFactory::getList()->{$page->mName} = $page; - } - - /** * Add a page to a certain display group for Special:SpecialPages * * @param $page Mixed: SpecialPage or string @@ -148,7 +134,7 @@ class SpecialPage { * preferred method is now to add a SpecialPage_initList hook. * @deprecated since 1.18 * - * @param $name String the page to remove + * @param string $name the page to remove */ static function removePage( $name ) { wfDeprecated( __METHOD__, '1.18' ); @@ -158,7 +144,7 @@ class SpecialPage { /** * Check if a given name exist as a special page or as a special page alias * - * @param $name String: name of a special page + * @param string $name name of a special page * @return Boolean: true if a special page exists with this name * @deprecated since 1.18 call SpecialPageFactory method directly */ @@ -266,13 +252,15 @@ class SpecialPage { * Get a localised Title object for a specified special page name * * @param $name String - * @param $subpage String|Bool subpage string, or false to not use a subpage + * @param string|Bool $subpage subpage string, or false to not use a subpage + * @param string $fragment the link fragment (after the "#") + * @throws MWException * @return Title object */ - public static function getTitleFor( $name, $subpage = false ) { + public static function getTitleFor( $name, $subpage = false, $fragment = '' ) { $name = SpecialPageFactory::getLocalNameFor( $name, $subpage ); if ( $name ) { - return Title::makeTitle( NS_SPECIAL, $name ); + return Title::makeTitle( NS_SPECIAL, $name, $fragment ); } else { throw new MWException( "Invalid special page name \"$name\"" ); } @@ -282,7 +270,7 @@ class SpecialPage { * Get a localised Title object for a page name with a possibly unvalidated subpage * * @param $name String - * @param $subpage String|Bool subpage string, or false to not use a subpage + * @param string|Bool $subpage subpage string, or false to not use a subpage * @return Title object or null if the page doesn't exist */ public static function getSafeTitleFor( $name, $subpage = false ) { @@ -313,15 +301,17 @@ class SpecialPage { * be displayed by the default execute() method, without the global function ever * being called. * - * If you override execute(), you can recover the default behaviour with userCanExecute() + * If you override execute(), you can recover the default behavior with userCanExecute() * and displayRestrictionError() * - * @param $name String: name of the special page, as seen in links and URLs - * @param $restriction String: user right required, e.g. "block" or "delete" - * @param $listed Bool: whether the page is listed in Special:Specialpages - * @param $function Callback|Bool: function called by execute(). By default it is constructed from $name - * @param $file String: file which is included by execute(). It is also constructed from $name by default - * @param $includable Bool: whether the page can be included in normal pages + * @param string $name Name of the special page, as seen in links and URLs + * @param string $restriction User right required, e.g. "block" or "delete" + * @param bool $listed Whether the page is listed in Special:Specialpages + * @param Callback|Bool $function Function called by execute(). By default + * it is constructed from $name + * @param string $file File which is included by execute(). It is also + * constructed from $name by default + * @param bool $includable Whether the page can be included in normal pages */ public function __construct( $name = '', $restriction = '', $listed = true, @@ -333,12 +323,14 @@ class SpecialPage { /** * Do the real work for the constructor, mainly so __call() can intercept * calls to SpecialPage() - * @param $name String: name of the special page, as seen in links and URLs - * @param $restriction String: user right required, e.g. "block" or "delete" - * @param $listed Bool: whether the page is listed in Special:Specialpages - * @param $function Callback|Bool: function called by execute(). By default it is constructed from $name - * @param $file String: file which is included by execute(). It is also constructed from $name by default - * @param $includable Bool: whether the page can be included in normal pages + * @param string $name Name of the special page, as seen in links and URLs + * @param string $restriction User right required, e.g. "block" or "delete" + * @param bool $listed Whether the page is listed in Special:Specialpages + * @param Callback|Bool $function Function called by execute(). By default + * it is constructed from $name + * @param string $file File which is included by execute(). It is also + * constructed from $name by default + * @param bool $includable Whether the page can be included in normal pages */ private function init( $name, $restriction, $listed, $function, $file, $includable ) { $this->mName = $name; @@ -361,8 +353,9 @@ class SpecialPage { * Use PHP's magic __call handler to get calls to the old PHP4 constructor * because PHP E_STRICT yells at you for having __construct() and SpecialPage() * - * @param $fName String Name of called method - * @param $a Array Arguments to the method + * @param string $fName Name of called method + * @param array $a Arguments to the method + * @throws MWException * @deprecated since 1.17, call parent::__construct() */ public function __call( $fName, $a ) { @@ -455,7 +448,10 @@ class SpecialPage { * @return Mixed * @deprecated since 1.18 */ - function name( $x = null ) { wfDeprecated( __METHOD__, '1.18' ); return wfSetVar( $this->mName, $x ); } + function name( $x = null ) { + wfDeprecated( __METHOD__, '1.18' ); + return wfSetVar( $this->mName, $x ); + } /** * These mutators are very evil, as the relevant variables should not mutate. So @@ -464,7 +460,10 @@ class SpecialPage { * @return Mixed * @deprecated since 1.18 */ - function restriction( $x = null ) { wfDeprecated( __METHOD__, '1.18' ); return wfSetVar( $this->mRestriction, $x ); } + function restriction( $x = null ) { + wfDeprecated( __METHOD__, '1.18' ); + return wfSetVar( $this->mRestriction, $x ); + } /** * These mutators are very evil, as the relevant variables should not mutate. So @@ -473,7 +472,10 @@ class SpecialPage { * @return Mixed * @deprecated since 1.18 */ - function func( $x = null ) { wfDeprecated( __METHOD__, '1.18' ); return wfSetVar( $this->mFunction, $x ); } + function func( $x = null ) { + wfDeprecated( __METHOD__, '1.18' ); + return wfSetVar( $this->mFunction, $x ); + } /** * These mutators are very evil, as the relevant variables should not mutate. So @@ -482,7 +484,10 @@ class SpecialPage { * @return Mixed * @deprecated since 1.18 */ - function file( $x = null ) { wfDeprecated( __METHOD__, '1.18' ); return wfSetVar( $this->mFile, $x ); } + function file( $x = null ) { + wfDeprecated( __METHOD__, '1.18' ); + return wfSetVar( $this->mFile, $x ); + } /** * These mutators are very evil, as the relevant variables should not mutate. So @@ -491,7 +496,10 @@ class SpecialPage { * @return Mixed * @deprecated since 1.18 */ - function includable( $x = null ) { wfDeprecated( __METHOD__, '1.18' ); return wfSetVar( $this->mIncludable, $x ); } + function includable( $x = null ) { + wfDeprecated( __METHOD__, '1.18' ); + return wfSetVar( $this->mIncludable, $x ); + } /** * Whether the special page is being evaluated via transclusion @@ -525,6 +533,19 @@ class SpecialPage { } /** + * Is this page cached? + * Expensive pages are cached or disabled in miser mode. + * Used by QueryPage and subclasses, moved here so that + * Special:SpecialPages can safely call it for all special pages. + * + * @return Boolean + * @since 1.21 + */ + public function isCached() { + return false; + } + + /** * Can be overridden by subclasses with more complicated permissions * schemes. * @@ -532,9 +553,8 @@ class SpecialPage { * pages? */ public function isRestricted() { - global $wgGroupPermissions; - // DWIM: If all anons can do something, then it is not restricted - return $this->mRestriction != '' && empty( $wgGroupPermissions['*'][$this->mRestriction] ); + // DWIM: If anons can do something, then it is not restricted + return $this->mRestriction != '' && !User::groupHasPermission( '*', $this->mRestriction ); } /** @@ -596,7 +616,7 @@ class SpecialPage { * * @param $subPage string|null */ - public final function run( $subPage ) { + final public function run( $subPage ) { /** * Gets called before @see SpecialPage::execute. * @@ -659,7 +679,7 @@ class SpecialPage { $func = $this->mFunction; // only load file if the function does not exist if ( !is_callable( $func ) && $this->mFile ) { - require_once( $this->mFile ); + require_once $this->mFile; } $this->outputHeader(); call_user_func( $func, $subPage, $this ); @@ -668,10 +688,10 @@ class SpecialPage { /** * Outputs a summary message on top of special pages * Per default the message key is the canonical name of the special page - * May be overriden, i.e. by extensions to stick with the naming conventions + * May be overridden, i.e. by extensions to stick with the naming conventions * for message keys: 'extensionname-xxx' * - * @param $summaryMessageKey String: message key of the summary + * @param string $summaryMessageKey message key of the summary */ function outputHeader( $summaryMessageKey = '' ) { global $wgContLang; @@ -693,7 +713,7 @@ class SpecialPage { * also the name that will be listed in Special:Specialpages * * Derived classes can override this, but usually it is easier to keep the - * default behaviour. Messages can be added at run-time, see + * default behavior. Messages can be added at run-time, see * MessageCache.php. * * @return String @@ -732,7 +752,8 @@ class SpecialPage { if ( $this->mContext instanceof IContextSource ) { return $this->mContext; } else { - wfDebug( __METHOD__ . " called and \$mContext is null. Return RequestContext::getMain(); for sanity\n" ); + wfDebug( __METHOD__ . " called and \$mContext is null. " . + "Return RequestContext::getMain(); for sanity\n" ); return RequestContext::getMain(); } } @@ -780,7 +801,7 @@ class SpecialPage { /** * Shortcut to get user's language * - * @deprecated 1.19 Use getLanguage instead + * @deprecated since 1.19 Use getLanguage instead * @return Language * @since 1.18 */ @@ -825,7 +846,7 @@ class SpecialPage { // RequestContext passes context to wfMessage, and the language is set from // the context, but setting the language for Message class removes the // interface message status, which breaks for example usernameless gender - // invokations. Restore the flag when not including special page in content. + // invocations. Restore the flag when not including special page in content. if ( $this->including() ) { $message->setInterfaceMessageFlag( false ); } @@ -840,14 +861,65 @@ class SpecialPage { protected function addFeedLinks( $params ) { global $wgFeedClasses; - $feedTemplate = wfScript( 'api' ) . '?'; + $feedTemplate = wfScript( 'api' ); foreach ( $wgFeedClasses as $format => $class ) { $theseParams = $params + array( 'feedformat' => $format ); - $url = $feedTemplate . wfArrayToCGI( $theseParams ); + $url = wfAppendQuery( $feedTemplate, $theseParams ); $this->getOutput()->addFeedLink( $format, $url ); } } + + /** + * Get the group that the special page belongs in on Special:SpecialPage + * Use this method, instead of getGroupName to allow customization + * of the group name from the wiki side + * + * @return string Group of this special page + * @since 1.21 + */ + public function getFinalGroupName() { + global $wgSpecialPageGroups; + $name = $this->getName(); + $group = '-'; + + // Allow overbidding the group from the wiki side + $msg = $this->msg( 'specialpages-specialpagegroup-' . strtolower( $name ) )->inContentLanguage(); + if ( !$msg->isBlank() ) { + $group = $msg->text(); + } else { + // Than use the group from this object + $group = $this->getGroupName(); + + // Group '-' is used as default to have the chance to determine, + // if the special pages overrides this method, + // if not overridden, $wgSpecialPageGroups is checked for b/c + if ( $group === '-' && isset( $wgSpecialPageGroups[$name] ) ) { + $group = $wgSpecialPageGroups[$name]; + } + } + + // never give '-' back, change to 'other' + if ( $group === '-' ) { + $group = 'other'; + } + + return $group; + } + + /** + * Under which header this special page is listed in Special:SpecialPages + * See messages 'specialpages-group-*' for valid names + * This method defaults to group 'other' + * + * @return string + * @since 1.21 + */ + protected function getGroupName() { + // '-' used here to determine, if this group is overridden or has a hardcoded 'other' + // Needed for b/c in getFinalGroupName + return '-'; + } } /** @@ -856,43 +928,77 @@ class SpecialPage { * a new structure for SpecialPages */ abstract class FormSpecialPage extends SpecialPage { + /** + * The sub-page of the special page. + * @var string + */ + protected $par = null; /** * Get an HTMLForm descriptor array * @return Array */ - protected abstract function getFormFields(); + abstract protected function getFormFields(); /** - * Add pre- or post-text to the form + * Add pre-text to the form * @return String HTML which will be sent to $form->addPreText() */ - protected function preText() { return ''; } - protected function postText() { return ''; } + protected function preText() { + return ''; + } + + /** + * Add post-text to the form + * @return String HTML which will be sent to $form->addPostText() + */ + protected function postText() { + return ''; + } /** * Play with the HTMLForm if you need to more substantially * @param $form HTMLForm */ - protected function alterForm( HTMLForm $form ) {} + protected function alterForm( HTMLForm $form ) { + } + + /** + * Get message prefix for HTMLForm + * + * @since 1.21 + * @return string + */ + protected function getMessagePrefix() { + return strtolower( $this->getName() ); + } /** - * Get the HTMLForm to control behaviour + * Get the HTMLForm to control behavior * @return HTMLForm|null */ protected function getForm() { $this->fields = $this->getFormFields(); - $form = new HTMLForm( $this->fields, $this->getContext() ); + $form = new HTMLForm( $this->fields, $this->getContext(), $this->getMessagePrefix() ); $form->setSubmitCallback( array( $this, 'onSubmit' ) ); - $form->setWrapperLegend( $this->msg( strtolower( $this->getName() ) . '-legend' ) ); - $form->addHeaderText( - $this->msg( strtolower( $this->getName() ) . '-text' )->parseAsBlock() ); + // If the form is a compact vertical form, then don't output this ugly + // fieldset surrounding it. + // XXX Special pages can setDisplayFormat to 'vform' in alterForm(), but that + // is called after this. + if ( !$form->isVForm() ) { + $form->setWrapperLegendMsg( $this->getMessagePrefix() . '-legend' ); + } + + $headerMsg = $this->msg( $this->getMessagePrefix() . '-text' ); + if ( !$headerMsg->isDisabled() ) { + $form->addHeaderText( $headerMsg->parseAsBlock() ); + } // Retain query parameters (uselang etc) $params = array_diff_key( $this->getRequest()->getQueryValues(), array( 'title' => null ) ); - $form->addHiddenField( 'redirectparams', wfArrayToCGI( $params ) ); + $form->addHiddenField( 'redirectparams', wfArrayToCgi( $params ) ); $form->addPreText( $this->preText() ); $form->addPostText( $this->postText() ); @@ -909,18 +1015,20 @@ abstract class FormSpecialPage extends SpecialPage { * @param $data Array * @return Bool|Array true for success, false for didn't-try, array of errors on failure */ - public abstract function onSubmit( array $data ); + abstract public function onSubmit( array $data ); /** * Do something exciting on successful processing of the form, most likely to show a * confirmation message + * @since 1.22 Default is to do nothing */ - public abstract function onSuccess(); + public function onSuccess() { + } /** * Basic SpecialPage workflow: get a form, send it to the user; get some data back, * - * @param $par String Subpage string if one was specified + * @param string $par Subpage string if one was specified */ public function execute( $par ) { $this->setParameter( $par ); @@ -937,16 +1045,18 @@ abstract class FormSpecialPage extends SpecialPage { /** * Maybe do something interesting with the subpage parameter - * @param $par String + * @param string $par */ - protected function setParameter( $par ) {} + protected function setParameter( $par ) { + $this->par = $par; + } /** * Called from execute() to check if the given user can perform this action. * Failures here must throw subclasses of ErrorPageError. * @param $user User + * @throws UserBlockedError * @return Bool true - * @throws ErrorPageError */ protected function checkExecutePermissions( User $user ) { $this->checkPermissions(); @@ -1019,7 +1129,7 @@ abstract class RedirectSpecialPage extends UnlistedSpecialPage { // Query parameters that can be passed through redirects protected $mAllowedRedirectParams = array(); - // Query parameteres added by redirects + // Query parameters added by redirects protected $mAddedRedirectParams = array(); public function execute( $par ) { @@ -1027,19 +1137,16 @@ abstract class RedirectSpecialPage extends UnlistedSpecialPage { $query = $this->getRedirectQuery(); // Redirect to a page title with possible query parameters if ( $redirect instanceof Title ) { - $url = $redirect->getFullUrl( $query ); + $url = $redirect->getFullURL( $query ); $this->getOutput()->redirect( $url ); - wfProfileOut( __METHOD__ ); return $redirect; - // Redirect to index.php with query parameters } elseif ( $redirect === true ) { - global $wgScript; - $url = $wgScript . '?' . wfArrayToCGI( $query ); + // Redirect to index.php with query parameters + $url = wfAppendQuery( wfScript( 'index' ), $query ); $this->getOutput()->redirect( $url ); - wfProfileOut( __METHOD__ ); return $redirect; } else { - $class = __CLASS__; + $class = get_class( $this ); throw new MWException( "RedirectSpecialPage $class doesn't redirect!" ); } } @@ -1048,7 +1155,7 @@ abstract class RedirectSpecialPage extends UnlistedSpecialPage { * If the special page is a redirect, then get the Title object it redirects to. * False otherwise. * - * @param $par String Subpage string + * @param string $par Subpage string * @return Title|bool */ abstract public function getRedirect( $par ); @@ -1079,6 +1186,7 @@ abstract class RedirectSpecialPage extends UnlistedSpecialPage { } abstract class SpecialRedirectToSpecial extends RedirectSpecialPage { + // @todo FIXME: Visibility must be declared var $redirName, $redirSubpage; function __construct( @@ -1125,12 +1233,21 @@ class SpecialListBots extends SpecialRedirectToSpecial { */ class SpecialCreateAccount extends SpecialRedirectToSpecial { function __construct() { - parent::__construct( 'CreateAccount', 'Userlogin', 'signup', array( 'uselang' ) ); + parent::__construct( 'CreateAccount', 'Userlogin', 'signup', array( 'returnto', 'returntoquery', 'uselang' ) ); + } + + // No reason to hide this link on Special:Specialpages + public function isListed() { + return true; + } + + protected function getGroupName() { + return 'login'; } } /** * SpecialMypage, SpecialMytalk and SpecialMycontributions special pages - * are used to get user independant links pointing to the user page, talk + * are used to get user independent links pointing to the user page, talk * page and list of contributions. * This can let us cache a single copy of any generated content for all * users. @@ -1155,7 +1272,7 @@ class SpecialCreateAccount extends SpecialRedirectToSpecial { * - limit, offset: Useful for linking to history of one's own user page or * user talk page. For example, this would be a link to "the last edit to your * user talk page in the year 2010": - * http://en.wikipedia.org/w/index.php?title=Special:MyPage&offset=20110000000000&limit=1&action=history + * http://en.wikipedia.org/wiki/Special:MyPage?offset=20110000000000&limit=1&action=history * * - feed: would allow linking to the current user's RSS feed for their user * talk page: @@ -1209,9 +1326,9 @@ abstract class RedirectSpecialArticle extends RedirectSpecialPage { 'action', 'redirect', 'rdfrom', # Options for preloaded edits - 'preload', 'editintro', 'preloadtitle', 'summary', + 'preload', 'editintro', 'preloadtitle', 'summary', 'nosummary', # Options for overriding user settings - 'preview', 'internaledit', 'externaledit', 'mode', + 'preview', 'internaledit', 'externaledit', 'mode', 'minor', 'watchthis', # Options for history/diffs 'section', 'oldid', 'diff', 'dir', 'limit', 'offset', 'feed', @@ -1221,7 +1338,7 @@ abstract class RedirectSpecialArticle extends RedirectSpecialPage { 'ctype', 'maxage', 'smaxage', ); - wfRunHooks( "RedirectSpecialArticleRedirectParams", array(&$redirectParams) ); + wfRunHooks( "RedirectSpecialArticleRedirectParams", array( &$redirectParams ) ); $this->mAllowedRedirectParams = $redirectParams; } } @@ -1268,7 +1385,7 @@ class SpecialMytalk extends RedirectSpecialArticle { */ class SpecialMycontributions extends RedirectSpecialPage { function __construct() { - parent::__construct( 'Mycontributions' ); + parent::__construct( 'Mycontributions' ); $this->mAllowedRedirectParams = array( 'limit', 'namespace', 'tagfilter', 'offset', 'dir', 'year', 'month', 'feed' ); } @@ -1284,7 +1401,7 @@ class SpecialMycontributions extends RedirectSpecialPage { class SpecialMyuploads extends RedirectSpecialPage { function __construct() { parent::__construct( 'Myuploads' ); - $this->mAllowedRedirectParams = array( 'limit' ); + $this->mAllowedRedirectParams = array( 'limit', 'ilshowall', 'ilsearch' ); } function getRedirect( $subpage ) { @@ -1293,6 +1410,22 @@ class SpecialMyuploads extends RedirectSpecialPage { } /** + * Redirect Special:Listfiles?user=$wgUser&ilshowall=true + */ +class SpecialAllMyUploads extends RedirectSpecialPage { + function __construct() { + parent::__construct( 'AllMyUploads' ); + $this->mAllowedRedirectParams = array( 'limit', 'ilsearch' ); + } + + function getRedirect( $subpage ) { + $this->mAddedRedirectParams['ilshowall'] = 1; + return SpecialPage::getTitleFor( 'Listfiles', $this->getUser()->getName() ); + } +} + + +/** * Redirect from Special:PermanentLink/### to index.php?oldid=### */ class SpecialPermanentLink extends RedirectSpecialPage { |