From 02e44a71b036783edc6ffba29068f9ea9d311fbc Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Mon, 25 Apr 2011 18:20:53 +0000 Subject: [PATCH] Revert r86872: Breaks LiquidThreads page moves with the below failure. Threads are lost and nowhere to be found any more. [25-Apr-2011 18:12:45] /wiki/Special:MoveThread/Thread:User_talk:Siebrand/test/One_new_message: Exception: MWNamespace::getTalk does not make any sense for given namespace -1 #0 /www/w/includes/Namespace.php(81): MWNamespace::isMethodValidFor(-1, 'MWNamespace::ge...') #1 /www/w/includes/WatchedItem.php(73): MWNamespace::getTalk(-1) #2 /www/w/includes/User.php(2304): WatchedItem->addWatch() #3 /www/w/includes/actions/WatchAction.php(53): User->addWatch(Object(Title)) #4 /www/w/includes/Action.php(376): WatchAction->onView() #5 /www/w/extensions/LiquidThreads/classes/Thread.php(115): FormlessAction->execute() #6 /www/w/extensions/LiquidThreads/classes/Thread.php(435): Thread::create(Object(Article), Object(Article), NULL, 1, 'One new message') #7 /www/w/extensions/LiquidThreads/classes/Thread.php(414): Thread->leaveTrace('move test', Object(Title), Object(Title)) #8 /www/w/extensions/LiquidThreads/pages/SpecialMoveThread.php(107): Thread->moveToPage(Object(Title), 'move test', true) #9 [internal function]: SpecialMoveThread->trySubmit(Array) #10 /www/w/includes/HTMLForm.php(279): call_user_func(Array, Array) #11 /www/w/includes/HTMLForm.php(228): HTMLForm->trySubmit() #12 /www/w/includes/HTMLForm.php(242): HTMLForm->tryAuthorizedSubmit() #13 /www/w/extensions/LiquidThreads/pages/ThreadActionPage.php(37): HTMLForm->show() #14 /www/w/includes/SpecialPageFactory.php(459): ThreadActionPage->execute('Thread:User_tal...') #15 /www/w/includes/Wiki.php(252): SpecialPageFactory::executePath(Object(Title), Object(RequestContext)) #16 /www/w/includes/Wiki.php(98): MediaWiki->handleSpecialCases() #17 /www/w/index.php(145): MediaWiki->performRequestForTitle(NULL) #18 {main} --- includes/Action.php | 78 +++++++++++++++++++-- includes/AutoLoader.php | 2 - includes/HTMLForm.php | 38 +++++++++-- includes/OutputPage.php | 64 +++++++++++++++-- includes/RequestContext.php | 133 +----------------------------------- includes/Skin.php | 93 ++++++++++++++++--------- includes/SpecialPage.php | 56 ++++++++++++++- 7 files changed, 277 insertions(+), 187 deletions(-) diff --git a/includes/Action.php b/includes/Action.php index 032d0949b5..5fbb5c7013 100644 --- a/includes/Action.php +++ b/includes/Action.php @@ -23,12 +23,16 @@ * * @file */ -abstract class Action extends ContextSource { +abstract class Action { // Page on which we're performing the action // @var Article protected $page; + // RequestContext if specified; otherwise we'll use the Context from the Page + // @var RequestContext + protected $context; + // The fields used to create the HTMLForm // @var Array protected $fields; @@ -86,6 +90,70 @@ abstract class Action extends ContextSource { return self::getClass( $name ) !== null; } + /** + * Get the RequestContext in use here + * @return RequestContext + */ + protected final function getContext() { + if ( $this->context instanceof RequestContext ) { + return $this->context; + } + return $this->page->getContext(); + } + + /** + * Get the WebRequest being used for this instance + * + * @return WebRequest + */ + protected final function getRequest() { + return $this->getContext()->request; + } + + /** + * Get the OutputPage being used for this instance + * + * @return OutputPage + */ + protected final function getOutput() { + return $this->getContext()->output; + } + + /** + * Shortcut to get the User being used for this instance + * + * @return User + */ + protected final function getUser() { + return $this->getContext()->user; + } + + /** + * Shortcut to get the Skin being used for this instance + * + * @return Skin + */ + protected final function getSkin() { + return $this->getContext()->skin; + } + + /** + * Shortcut to get the user Language being used for this instance + * + * @return Skin + */ + protected final function getLang() { + return $this->getContext()->lang; + } + + /** + * Shortcut to get the Title object from the page + * @return Title + */ + protected final function getTitle() { + return $this->page->getTitle(); + } + /** * Protected constructor: use Action::factory( $action, $page ) to actually build * these things in the real world @@ -93,7 +161,6 @@ abstract class Action extends ContextSource { */ protected function __construct( Article $page ) { $this->page = $page; - $this->setContext( $page->getContext() ); } /** @@ -282,7 +349,7 @@ abstract class FormAction extends Action { public function execute( array $data = null, $captureErrors = true ) { try { // Set a new context so output doesn't leak. - $this->setContext( clone $this->page->getContext() ); + $this->context = clone $this->page->getContext(); // This will throw exceptions if there's a problem $this->checkCanExecute( $this->getUser() ); @@ -364,11 +431,10 @@ abstract class FormlessAction extends Action { public function execute( array $data = null, $captureErrors = true ) { try { // Set a new context so output doesn't leak. - $context = clone $this->page->getContext(); + $this->context = clone $this->page->getContext(); if ( is_array( $data ) ) { - $context->setRequest( new FauxRequest( $data, false ) ); + $this->context->setRequest( new FauxRequest( $data, false ) ); } - $this->setContext( $context ); // This will throw exceptions if there's a problem $this->checkCanExecute( $this->getUser() ); diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index 1be417334c..b56929501a 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -49,7 +49,6 @@ $wgAutoloadLocalClasses = array( 'ConfEditorParseError' => 'includes/ConfEditor.php', 'ConfEditorToken' => 'includes/ConfEditor.php', 'ConstantDependency' => 'includes/CacheDependency.php', - 'ContextSource' => 'includes/RequestContext.php', 'Cookie' => 'includes/Cookie.php', 'CookieJar' => 'includes/Cookie.php', 'CreativeCommonsRdf' => 'includes/Metadata.php', @@ -124,7 +123,6 @@ $wgAutoloadLocalClasses = array( 'HTMLTextField' => 'includes/HTMLForm.php', 'Http' => 'includes/HttpFunctions.php', 'HttpRequest' => 'includes/HttpFunctions.old.php', - 'IContextSource' => 'includes/RequestContext.php', 'IcuCollation' => 'includes/Collation.php', 'ImageGallery' => 'includes/ImageGallery.php', 'ImageHistoryList' => 'includes/ImagePage.php', diff --git a/includes/HTMLForm.php b/includes/HTMLForm.php index 2e88257901..c7cf929b20 100644 --- a/includes/HTMLForm.php +++ b/includes/HTMLForm.php @@ -53,7 +53,7 @@ * * TODO: Document 'section' / 'subsection' stuff */ -class HTMLForm extends ContextSource { +class HTMLForm { # A mapping of 'type' inputs onto standard HTMLFormField subclasses static $typeMappings = array( @@ -102,6 +102,7 @@ class HTMLForm extends ContextSource { protected $mSubmitText; protected $mSubmitTooltip; + protected $mContext; // setContext( $context ); + $this->mContext = $context; $this->mTitle = false; // We don't need them to set a title $this->mMessagePrefix = $messagePrefix; } else { - $this->setContext( RequestContext::getMain() ); // B/C since 1.18 if( is_string( $context ) && $messagePrefix === '' ){ // it's actually $messagePrefix @@ -623,10 +623,40 @@ class HTMLForm extends ContextSource { */ function getTitle() { return $this->mTitle === false - ? parent::getTitle() + ? $this->getContext()->title : $this->mTitle; } + /** + * @return RequestContext + */ + public function getContext(){ + return $this->mContext instanceof RequestContext + ? $this->mContext + : RequestContext::getMain(); + } + + /** + * @return OutputPage + */ + public function getOutput(){ + return $this->getContext()->output; + } + + /** + * @return WebRequest + */ + public function getRequest(){ + return $this->getContext()->request; + } + + /** + * @return User + */ + public function getUser(){ + return $this->getContext()->user; + } + /** * Set the method used to submit the form * @param $method String diff --git a/includes/OutputPage.php b/includes/OutputPage.php index f8cdee6be8..eeaca5cf5b 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -18,7 +18,7 @@ if ( !defined( 'MEDIAWIKI' ) ) { * * @todo document */ -class OutputPage extends ContextSource { +class OutputPage { /// Should be private. Used with addMeta() which adds var $mMetatags = array(); @@ -220,13 +220,11 @@ class OutputPage extends ContextSource { * a OutputPage tied to that context. */ function __construct( RequestContext $context = null ) { - if ( $context === null ) { + if ( !isset($context) ) { # Extensions should use `new RequestContext` instead of `new OutputPage` now. wfDeprecated( __METHOD__ ); - $this->setContext( RequestContext::getMain() ); - } else { - $this->setContext( $context ); } + $this->mContext = $context; } /** @@ -765,6 +763,29 @@ class OutputPage extends ContextSource { return $this->mPagetitle; } + /** + * Get the RequestContext used in this instance + * + * @return RequestContext + */ + private function getContext() { + if ( !isset($this->mContext) ) { + wfDebug( __METHOD__ . " called and \$mContext is null. Using RequestContext::getMain(); for sanity\n" ); + $this->mContext = RequestContext::getMain(); + } + return $this->mContext; + } + + /** + * Get the WebRequest being used for this instance + * + * @return WebRequest + * @since 1.18 + */ + public function getRequest() { + return $this->getContext()->getRequest(); + } + /** * Set the Title object to use * @@ -774,6 +795,35 @@ class OutputPage extends ContextSource { $this->getContext()->setTitle( $t ); } + /** + * Get the Title object used in this instance + * + * @return Title + */ + public function getTitle() { + return $this->getContext()->getTitle(); + } + + /** + * Get the User object used in this instance + * + * @return User + * @since 1.18 + */ + public function getUser() { + return $this->getContext()->getUser(); + } + + /** + * Get the Skin object used to render this instance + * + * @return Skin + * @since 1.18 + */ + public function getSkin() { + return $this->getContext()->getSkin(); + } + /** * Replace the subtile with $str * @@ -2127,7 +2177,7 @@ class OutputPage extends ContextSource { ? 'lag-warn-normal' : 'lag-warn-high'; $wrap = Html::rawElement( 'div', array( 'class' => "mw-{$message}" ), "\n$1\n" ); - $this->wrapWikiMsg( "$wrap\n", array( $message, $this->getLang()->formatNum( $lag ) ) ); + $this->wrapWikiMsg( "$wrap\n", array( $message, $this->getContext()->getLang()->formatNum( $lag ) ) ); } } @@ -2273,7 +2323,7 @@ class OutputPage extends ContextSource { $dir = wfUILang()->getDir(); $bodyAttrs['class'] = "mediawiki $dir"; - if ( $this->getLang()->capitalizeAllNouns() ) { + if ( $this->getContext()->getLang()->capitalizeAllNouns() ) { # A class is probably not the best way to do this . . . $bodyAttrs['class'] .= ' capitalize-all-nouns'; } diff --git a/includes/RequestContext.php b/includes/RequestContext.php index b5d7fe18a9..d90ddd0f94 100644 --- a/includes/RequestContext.php +++ b/includes/RequestContext.php @@ -7,7 +7,7 @@ * @file */ -class RequestContext implements IContextSource { +class RequestContext { private $mRequest; // / WebRequest object private $mTitle; // / Title object private $mOutput; // / OutputPage object @@ -205,134 +205,3 @@ class RequestContext implements IContextSource { } } -/** - * Interface for objects which can provide a context on request. - */ -interface IContextSource { - - /** - * Get the WebRequest object - * - * @return WebRequest - */ - public function getRequest(); - - /** - * Get the Title object - * - * @return Title - */ - public function getTitle(); - - /** - * Get the OutputPage object - * - * @return OutputPage object - */ - public function getOutput(); - - /** - * Get the User object - * - * @return User - */ - public function getUser(); - - /** - * Get the Language object - * - * @return Language - */ - public function getLang(); - - /** - * Get the Skin object - * - * @return Skin - */ - public function getSkin(); -} - -/** - * The simplest way of implementing IContextSource is to hold a RequestContext as a - * member variable and provide accessors to it. - */ -abstract class ContextSource implements IContextSource { - - /** - * @var RequestContext - */ - private $context; - - /** - * Get the RequestContext object - * - * @return RequestContext - */ - public function getContext() { - return $this->context; - } - - /** - * Set the RequestContext object - * - * @param $context RequestContext - */ - public function setContext( RequestContext $context ) { - $this->context = $context; - } - - /** - * Get the WebRequest object - * - * @return WebRequest - */ - public function getRequest() { - return $this->context->getRequest(); - } - - /** - * Get the Title object - * - * @return Title - */ - public function getTitle() { - return $this->context->getTitle(); - } - - /** - * Get the OutputPage object - * - * @return OutputPage object - */ - public function getOutput() { - return $this->context->getOutput(); - } - - /** - * Get the User object - * - * @return User - */ - public function getUser() { - return $this->context->getUser(); - } - - /** - * Get the Language object - * - * @return Language - */ - public function getLang() { - return $this->context->getLang(); - } - - /** - * Get the Skin object - * - * @return Skin - */ - public function getSkin() { - return $this->context->getSkin(); - } -} \ No newline at end of file diff --git a/includes/Skin.php b/includes/Skin.php index 22ff359291..45fcaa2397 100644 --- a/includes/Skin.php +++ b/includes/Skin.php @@ -15,7 +15,7 @@ if ( !defined( 'MEDIAWIKI' ) ) { * * @ingroup Skins */ -abstract class Skin extends ContextSource { +abstract class Skin { /**#@+ * @private */ @@ -190,8 +190,10 @@ abstract class Skin extends ContextSource { * Preload the existence of three commonly-requested pages in a single query */ function preloadExistence() { + $user = $this->getContext()->getUser(); + // User/talk link - $titles = array( $this->getUser()->getUserPage(), $this->getUser()->getTalkPage() ); + $titles = array( $user->getUserPage(), $user->getTalkPage() ); // Other tab link if ( $this->getTitle()->getNamespace() == NS_SPECIAL ) { @@ -211,7 +213,7 @@ abstract class Skin extends ContextSource { * Set some local variables */ protected function setMembers() { - $this->userpage = $this->getUser()->getUserPage()->getPrefixedText(); + $this->userpage = $this->getContext()->getUser()->getUserPage()->getPrefixedText(); $this->usercss = false; } @@ -224,17 +226,42 @@ abstract class Skin extends ContextSource { return $this->mRevisionId == 0 || $this->mRevisionId == $this->getTitle()->getLatestRevID(); } + /** + * Set the RequestContext used in this instance + * + * @param RequestContext $context + */ + public function setContext( RequestContext $context ) { + $this->mContext = $context; + } + /** * Get the RequestContext used in this instance * * @return RequestContext */ public function getContext() { - if ( !parent::getContext() instanceof RequestContext ) { + if ( !isset($this->mContext) ) { wfDebug( __METHOD__ . " called and \$mContext is null. Using RequestContext::getMain(); for sanity\n" ); - $this->setContext( RequestContext::getMain() ); + $this->mContext = RequestContext::getMain(); } - return parent::getContext(); + return $this->mContext; + } + + /** Get the title + * + * @return Title + */ + public function getTitle() { + return $this->getContext()->getTitle(); + } + + /** Get the user + * + * @return User + */ + public function getUser() { + return $this->getContext()->getUser(); } /** @@ -328,7 +355,7 @@ abstract class Skin extends ContextSource { if ( $action != 'submit' ) { return false; } - if ( !$this->getRequest()->wasPosted() ) { + if ( !$this->getContext()->getRequest()->wasPosted() ) { return false; } if ( !$this->getTitle()->userCanEditCssSubpage() ) { @@ -338,8 +365,8 @@ abstract class Skin extends ContextSource { return false; } - return $this->getUser()->matchEditToken( - $this->getRequest()->getVal( 'wpEditToken' ) ); + return $this->getContext()->getUser()->matchEditToken( + $this->getContext()->getRequest()->getVal( 'wpEditToken' ) ); } /** @@ -401,16 +428,16 @@ abstract class Skin extends ContextSource { // Per-site custom styles if ( $wgUseSiteCss ) { $out->addModuleStyles( array( 'site', 'noscript' ) ); - if( $this->getUser()->isLoggedIn() ){ + if( $this->getContext()->getUser()->isLoggedIn() ){ $out->addModuleStyles( 'user.groups' ); } } // Per-user custom styles if ( $wgAllowUserCss ) { - if ( $this->getTitle()->isCssSubpage() && $this->userCanPreview( $this->getRequest()->getVal( 'action' ) ) ) { + if ( $this->getTitle()->isCssSubpage() && $this->userCanPreview( $this->getContext()->getRequest()->getVal( 'action' ) ) ) { // @FIXME: properly escape the cdata! - $out->addInlineStyle( $this->getRequest()->getText( 'wpTextbox1' ) ); + $out->addInlineStyle( $this->getContext()->getRequest()->getText( 'wpTextbox1' ) ); } else { $out->addModuleStyles( 'user' ); } @@ -500,7 +527,7 @@ abstract class Skin extends ContextSource { global $wgUseCategoryBrowser, $wgContLang; if( $out === null ){ - $out = $this->getOutput(); + $out = $this->getContext()->output; } if ( count( $out->mCategoryLinks ) == 0 ) { @@ -531,7 +558,7 @@ abstract class Skin extends ContextSource { # Hidden categories if ( isset( $allCats['hidden'] ) ) { - if ( $this->getUser()->getBoolOption( 'showhiddencats' ) ) { + if ( $this->getContext()->getUser()->getBoolOption( 'showhiddencats' ) ) { $class = 'mw-hidden-cats-user-shown'; } elseif ( $this->getTitle()->getNamespace() == NS_CATEGORY ) { $class = 'mw-hidden-cats-ns-shown'; @@ -602,7 +629,7 @@ abstract class Skin extends ContextSource { // Check what we're showing $allCats = $out->getCategoryLinks(); - $showHidden = $this->getUser()->getBoolOption( 'showhiddencats' ) || + $showHidden = $this->getContext()->getUser()->getBoolOption( 'showhiddencats' ) || $this->getTitle()->getNamespace() == NS_CATEGORY; if ( empty( $allCats['normal'] ) && !( !empty( $allCats['hidden'] ) && $showHidden ) ) { @@ -736,14 +763,14 @@ abstract class Skin extends ContextSource { } function getUndeleteLink() { - $action = $this->getRequest()->getVal( 'action', 'view' ); + $action = $this->getContext()->getRequest()->getVal( 'action', 'view' ); - if ( $this->getUser()->isAllowed( 'deletedhistory' ) && + if ( $this->getContext()->getUser()->isAllowed( 'deletedhistory' ) && ( $this->getTitle()->getArticleId() == 0 || $action == 'history' ) ) { $n = $this->getTitle()->isDeleted(); if ( $n ) { - if ( $this->getUser()->isAllowed( 'undelete' ) ) { + if ( $this->getContext()->getUser()->isAllowed( 'undelete' ) ) { $msg = 'thisisdeleted'; } else { $msg = 'viewdeleted'; @@ -753,7 +780,7 @@ abstract class Skin extends ContextSource { $msg, Linker::link( SpecialPage::getTitleFor( 'Undelete', $this->getTitle()->getPrefixedDBkey() ), - wfMsgExt( 'restorelink', array( 'parsemag', 'escape' ), $this->getLang()->formatNum( $n ) ), + wfMsgExt( 'restorelink', array( 'parsemag', 'escape' ), $this->getContext()->getLang()->formatNum( $n ) ), array(), array(), array( 'known', 'noclasses' ) @@ -766,10 +793,10 @@ abstract class Skin extends ContextSource { } /** - * The format with an explicit $out argument is deprecated + * The format without an explicit $out argument is deprecated */ function subPageSubtitle( OutputPage $out=null ) { - $out = $this->getOutput(); + $out = $this->getContext()->getOutput(); $subpages = ''; if ( !wfRunHooks( 'SkinSubPageSubtitle', array( &$subpages, $this, $out ) ) ) { @@ -791,7 +818,7 @@ abstract class Skin extends ContextSource { $linkObj = Title::newFromText( $growinglink ); if ( is_object( $linkObj ) && $linkObj->exists() ) { - $getlink = Linker::link( + $getlink = $this->link( $linkObj, htmlspecialchars( $display ), array(), @@ -841,7 +868,7 @@ abstract class Skin extends ContextSource { global $wgRightsPage, $wgRightsUrl, $wgRightsText; if ( $type == 'detect' ) { - $diff = $this->getRequest()->getVal( 'diff' ); + $diff = $this->getContext()->getRequest()->getVal( 'diff' ); if ( is_null( $diff ) && !$this->isRevisionCurrent() && wfMsgForContent( 'history_copyright' ) !== '-' ) { $type = 'history'; @@ -937,8 +964,8 @@ abstract class Skin extends ContextSource { } if ( $timestamp ) { - $d = $this->getLang()->date( $timestamp, true ); - $t = $this->getLang()->time( $timestamp, true ); + $d = $this->getContext()->getLang()->date( $timestamp, true ); + $t = $this->getContext()->getLang()->time( $timestamp, true ); $s = ' ' . wfMsg( 'lastmodifiedat', $d, $t ); } else { $s = ''; @@ -1065,7 +1092,7 @@ abstract class Skin extends ContextSource { function showEmailUser( $id ) { $targetUser = User::newFromId( $id ); - return $this->getUser()->canSendEmail() && # the sending user must have a confirmed email address + return $this->getContext()->getUser()->canSendEmail() && # the sending user must have a confirmed email address $targetUser->canReceiveEmail(); # the target user must have a confirmed email address and allow emails from users } @@ -1187,7 +1214,7 @@ abstract class Skin extends ContextSource { global $parserMemc, $wgEnableSidebarCache, $wgSidebarCacheExpiry; wfProfileIn( __METHOD__ ); - $key = wfMemcKey( 'sidebar', $this->getLang()->getCode() ); + $key = wfMemcKey( 'sidebar', $this->getContext()->getLang()->getCode() ); if ( $wgEnableSidebarCache ) { $cachedsidebar = $parserMemc->get( $key ); @@ -1323,9 +1350,9 @@ abstract class Skin extends ContextSource { * @return MediaWiki message or if no new talk page messages, nothing */ function getNewtalks() { - $out = $this->getOutput(); + $out = $this->getContext()->getOutput(); - $newtalks = $this->getUser()->getNewMessageLinks(); + $newtalks = $this->getContext()->getUser()->getNewMessageLinks(); $ntl = ''; if ( count( $newtalks ) == 1 && $newtalks[0]['wiki'] === wfWikiID() ) { @@ -1333,7 +1360,7 @@ abstract class Skin extends ContextSource { $userTalkTitle = $userTitle->getTalkPage(); if ( !$userTalkTitle->equals( $out->getTitle() ) ) { - $newMessagesLink = Linker::link( + $newMessagesLink = $this->link( $userTalkTitle, wfMsgHtml( 'newmessageslink' ), array(), @@ -1341,7 +1368,7 @@ abstract class Skin extends ContextSource { array( 'known', 'noclasses' ) ); - $newMessagesDiffLink = Linker::link( + $newMessagesDiffLink = $this->link( $userTalkTitle, wfMsgHtml( 'newmessagesdifflink' ), array(), @@ -1420,7 +1447,7 @@ abstract class Skin extends ContextSource { } if ( $needParse ) { - $parsed = $this->getOutput()->parse( $notice ); + $parsed = $this->getContext()->getOutput()->parse( $notice ); $parserMemc->set( $key, array( 'html' => $parsed, 'hash' => md5( $notice ) ), 600 ); $notice = $parsed; } @@ -1460,7 +1487,7 @@ abstract class Skin extends ContextSource { $siteNotice = ''; if ( wfRunHooks( 'SiteNoticeBefore', array( &$siteNotice, $this ) ) ) { - if ( $this->getUser() instanceof User && $this->getUser()->isLoggedIn() ) { + if ( is_object( $this->getContext()->getUser() ) && $this->getContext()->getUser()->isLoggedIn() ) { $siteNotice = $this->getCachedNotice( 'sitenotice' ); } else { $anonNotice = $this->getCachedNotice( 'anonnotice' ); diff --git a/includes/SpecialPage.php b/includes/SpecialPage.php index 49dfc7dba4..866cbecd5c 100644 --- a/includes/SpecialPage.php +++ b/includes/SpecialPage.php @@ -27,7 +27,7 @@ * page list. * @ingroup SpecialPage */ -class SpecialPage extends ContextSource { +class SpecialPage { // The canonical name of this special page // Also used for the default

heading, @see getDescription() @@ -572,6 +572,16 @@ class SpecialPage extends ContextSource { function getTitle( $subpage = false ) { return self::getTitleFor( $this->mName, $subpage ); } + + /** + * Sets the context this SpecialPage is executed in + * + * @param $context RequestContext + * @since 1.18 + */ + public function setContext( $context ) { + $this->mContext = $context; + } /** * Gets the context this SpecialPage is executed in @@ -580,14 +590,54 @@ class SpecialPage extends ContextSource { * @since 1.18 */ public function getContext() { - if ( parent::getContext() instanceof RequestContext ) { - return parent::getContext(); + if ( $this->mContext instanceof RequestContext ) { + return $this->mContext; } else { wfDebug( __METHOD__ . " called and \$mContext is null. Return RequestContext::getMain(); for sanity\n" ); return RequestContext::getMain(); } } + /** + * Get the WebRequest being used for this instance + * + * @return WebRequest + * @since 1.18 + */ + public function getRequest() { + return $this->getContext()->getRequest(); + } + + /** + * Get the OutputPage being used for this instance + * + * @return OutputPage + * @since 1.18 + */ + public function getOutput() { + return $this->getContext()->getOutput(); + } + + /** + * Shortcut to get the skin being used for this instance + * + * @return User + * @since 1.18 + */ + public function getUser() { + return $this->getContext()->getUser(); + } + + /** + * Shortcut to get the skin being used for this instance + * + * @return Skin + * @since 1.18 + */ + public function getSkin() { + return $this->getContext()->getSkin(); + } + /** * Return the full title, including $par * -- 2.20.1