From 70bdc008c4d977bc6df47c516709cde23770aca2 Mon Sep 17 00:00:00 2001 From: Happy-melon Date: Mon, 25 Apr 2011 17:37:43 +0000 Subject: [PATCH] Implement an interface and abstract class to hold the widely-reused get(Request|User|Title|Lang|Skin|Output) accessors for objects acting as a context source. Article is rather messier because both getTitle() and getUser() are in use for other things, and Article::$mTitle is in extremely wide use both within Article.php and outside. --- 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, 187 insertions(+), 277 deletions(-) diff --git a/includes/Action.php b/includes/Action.php index 5fbb5c7013..032d0949b5 100644 --- a/includes/Action.php +++ b/includes/Action.php @@ -23,16 +23,12 @@ * * @file */ -abstract class Action { +abstract class Action extends ContextSource { // 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; @@ -90,70 +86,6 @@ abstract class Action { 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 @@ -161,6 +93,7 @@ abstract class Action { */ protected function __construct( Article $page ) { $this->page = $page; + $this->setContext( $page->getContext() ); } /** @@ -349,7 +282,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->context = clone $this->page->getContext(); + $this->setContext( clone $this->page->getContext() ); // This will throw exceptions if there's a problem $this->checkCanExecute( $this->getUser() ); @@ -431,10 +364,11 @@ abstract class FormlessAction extends Action { public function execute( array $data = null, $captureErrors = true ) { try { // Set a new context so output doesn't leak. - $this->context = clone $this->page->getContext(); + $context = clone $this->page->getContext(); if ( is_array( $data ) ) { - $this->context->setRequest( new FauxRequest( $data, false ) ); + $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 b56929501a..1be417334c 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -49,6 +49,7 @@ $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', @@ -123,6 +124,7 @@ $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 c7cf929b20..2e88257901 100644 --- a/includes/HTMLForm.php +++ b/includes/HTMLForm.php @@ -53,7 +53,7 @@ * * TODO: Document 'section' / 'subsection' stuff */ -class HTMLForm { +class HTMLForm extends ContextSource { # A mapping of 'type' inputs onto standard HTMLFormField subclasses static $typeMappings = array( @@ -102,7 +102,6 @@ class HTMLForm { protected $mSubmitText; protected $mSubmitTooltip; - protected $mContext; // mContext = $context; + $this->setContext( $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,40 +623,10 @@ class HTMLForm { */ function getTitle() { return $this->mTitle === false - ? $this->getContext()->title + ? parent::getTitle() : $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 eeaca5cf5b..f8cdee6be8 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -18,7 +18,7 @@ if ( !defined( 'MEDIAWIKI' ) ) { * * @todo document */ -class OutputPage { +class OutputPage extends ContextSource { /// Should be private. Used with addMeta() which adds var $mMetatags = array(); @@ -220,11 +220,13 @@ class OutputPage { * a OutputPage tied to that context. */ function __construct( RequestContext $context = null ) { - if ( !isset($context) ) { + if ( $context === null ) { # Extensions should use `new RequestContext` instead of `new OutputPage` now. wfDeprecated( __METHOD__ ); + $this->setContext( RequestContext::getMain() ); + } else { + $this->setContext( $context ); } - $this->mContext = $context; } /** @@ -763,29 +765,6 @@ class OutputPage { 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 * @@ -795,35 +774,6 @@ class OutputPage { $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 * @@ -2177,7 +2127,7 @@ class OutputPage { ? 'lag-warn-normal' : 'lag-warn-high'; $wrap = Html::rawElement( 'div', array( 'class' => "mw-{$message}" ), "\n$1\n" ); - $this->wrapWikiMsg( "$wrap\n", array( $message, $this->getContext()->getLang()->formatNum( $lag ) ) ); + $this->wrapWikiMsg( "$wrap\n", array( $message, $this->getLang()->formatNum( $lag ) ) ); } } @@ -2323,7 +2273,7 @@ class OutputPage { $dir = wfUILang()->getDir(); $bodyAttrs['class'] = "mediawiki $dir"; - if ( $this->getContext()->getLang()->capitalizeAllNouns() ) { + if ( $this->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 d90ddd0f94..b5d7fe18a9 100644 --- a/includes/RequestContext.php +++ b/includes/RequestContext.php @@ -7,7 +7,7 @@ * @file */ -class RequestContext { +class RequestContext implements IContextSource { private $mRequest; // / WebRequest object private $mTitle; // / Title object private $mOutput; // / OutputPage object @@ -205,3 +205,134 @@ class RequestContext { } } +/** + * 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 45fcaa2397..22ff359291 100644 --- a/includes/Skin.php +++ b/includes/Skin.php @@ -15,7 +15,7 @@ if ( !defined( 'MEDIAWIKI' ) ) { * * @ingroup Skins */ -abstract class Skin { +abstract class Skin extends ContextSource { /**#@+ * @private */ @@ -190,10 +190,8 @@ abstract class Skin { * Preload the existence of three commonly-requested pages in a single query */ function preloadExistence() { - $user = $this->getContext()->getUser(); - // User/talk link - $titles = array( $user->getUserPage(), $user->getTalkPage() ); + $titles = array( $this->getUser()->getUserPage(), $this->getUser()->getTalkPage() ); // Other tab link if ( $this->getTitle()->getNamespace() == NS_SPECIAL ) { @@ -213,7 +211,7 @@ abstract class Skin { * Set some local variables */ protected function setMembers() { - $this->userpage = $this->getContext()->getUser()->getUserPage()->getPrefixedText(); + $this->userpage = $this->getUser()->getUserPage()->getPrefixedText(); $this->usercss = false; } @@ -226,42 +224,17 @@ abstract class Skin { 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 ( !isset($this->mContext) ) { + if ( !parent::getContext() instanceof RequestContext ) { wfDebug( __METHOD__ . " called and \$mContext is null. Using RequestContext::getMain(); for sanity\n" ); - $this->mContext = RequestContext::getMain(); + $this->setContext( RequestContext::getMain() ); } - 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(); + return parent::getContext(); } /** @@ -355,7 +328,7 @@ abstract class Skin { if ( $action != 'submit' ) { return false; } - if ( !$this->getContext()->getRequest()->wasPosted() ) { + if ( !$this->getRequest()->wasPosted() ) { return false; } if ( !$this->getTitle()->userCanEditCssSubpage() ) { @@ -365,8 +338,8 @@ abstract class Skin { return false; } - return $this->getContext()->getUser()->matchEditToken( - $this->getContext()->getRequest()->getVal( 'wpEditToken' ) ); + return $this->getUser()->matchEditToken( + $this->getRequest()->getVal( 'wpEditToken' ) ); } /** @@ -428,16 +401,16 @@ abstract class Skin { // Per-site custom styles if ( $wgUseSiteCss ) { $out->addModuleStyles( array( 'site', 'noscript' ) ); - if( $this->getContext()->getUser()->isLoggedIn() ){ + if( $this->getUser()->isLoggedIn() ){ $out->addModuleStyles( 'user.groups' ); } } // Per-user custom styles if ( $wgAllowUserCss ) { - if ( $this->getTitle()->isCssSubpage() && $this->userCanPreview( $this->getContext()->getRequest()->getVal( 'action' ) ) ) { + if ( $this->getTitle()->isCssSubpage() && $this->userCanPreview( $this->getRequest()->getVal( 'action' ) ) ) { // @FIXME: properly escape the cdata! - $out->addInlineStyle( $this->getContext()->getRequest()->getText( 'wpTextbox1' ) ); + $out->addInlineStyle( $this->getRequest()->getText( 'wpTextbox1' ) ); } else { $out->addModuleStyles( 'user' ); } @@ -527,7 +500,7 @@ abstract class Skin { global $wgUseCategoryBrowser, $wgContLang; if( $out === null ){ - $out = $this->getContext()->output; + $out = $this->getOutput(); } if ( count( $out->mCategoryLinks ) == 0 ) { @@ -558,7 +531,7 @@ abstract class Skin { # Hidden categories if ( isset( $allCats['hidden'] ) ) { - if ( $this->getContext()->getUser()->getBoolOption( 'showhiddencats' ) ) { + if ( $this->getUser()->getBoolOption( 'showhiddencats' ) ) { $class = 'mw-hidden-cats-user-shown'; } elseif ( $this->getTitle()->getNamespace() == NS_CATEGORY ) { $class = 'mw-hidden-cats-ns-shown'; @@ -629,7 +602,7 @@ abstract class Skin { // Check what we're showing $allCats = $out->getCategoryLinks(); - $showHidden = $this->getContext()->getUser()->getBoolOption( 'showhiddencats' ) || + $showHidden = $this->getUser()->getBoolOption( 'showhiddencats' ) || $this->getTitle()->getNamespace() == NS_CATEGORY; if ( empty( $allCats['normal'] ) && !( !empty( $allCats['hidden'] ) && $showHidden ) ) { @@ -763,14 +736,14 @@ abstract class Skin { } function getUndeleteLink() { - $action = $this->getContext()->getRequest()->getVal( 'action', 'view' ); + $action = $this->getRequest()->getVal( 'action', 'view' ); - if ( $this->getContext()->getUser()->isAllowed( 'deletedhistory' ) && + if ( $this->getUser()->isAllowed( 'deletedhistory' ) && ( $this->getTitle()->getArticleId() == 0 || $action == 'history' ) ) { $n = $this->getTitle()->isDeleted(); if ( $n ) { - if ( $this->getContext()->getUser()->isAllowed( 'undelete' ) ) { + if ( $this->getUser()->isAllowed( 'undelete' ) ) { $msg = 'thisisdeleted'; } else { $msg = 'viewdeleted'; @@ -780,7 +753,7 @@ abstract class Skin { $msg, Linker::link( SpecialPage::getTitleFor( 'Undelete', $this->getTitle()->getPrefixedDBkey() ), - wfMsgExt( 'restorelink', array( 'parsemag', 'escape' ), $this->getContext()->getLang()->formatNum( $n ) ), + wfMsgExt( 'restorelink', array( 'parsemag', 'escape' ), $this->getLang()->formatNum( $n ) ), array(), array(), array( 'known', 'noclasses' ) @@ -793,10 +766,10 @@ abstract class Skin { } /** - * The format without an explicit $out argument is deprecated + * The format with an explicit $out argument is deprecated */ function subPageSubtitle( OutputPage $out=null ) { - $out = $this->getContext()->getOutput(); + $out = $this->getOutput(); $subpages = ''; if ( !wfRunHooks( 'SkinSubPageSubtitle', array( &$subpages, $this, $out ) ) ) { @@ -818,7 +791,7 @@ abstract class Skin { $linkObj = Title::newFromText( $growinglink ); if ( is_object( $linkObj ) && $linkObj->exists() ) { - $getlink = $this->link( + $getlink = Linker::link( $linkObj, htmlspecialchars( $display ), array(), @@ -868,7 +841,7 @@ abstract class Skin { global $wgRightsPage, $wgRightsUrl, $wgRightsText; if ( $type == 'detect' ) { - $diff = $this->getContext()->getRequest()->getVal( 'diff' ); + $diff = $this->getRequest()->getVal( 'diff' ); if ( is_null( $diff ) && !$this->isRevisionCurrent() && wfMsgForContent( 'history_copyright' ) !== '-' ) { $type = 'history'; @@ -964,8 +937,8 @@ abstract class Skin { } if ( $timestamp ) { - $d = $this->getContext()->getLang()->date( $timestamp, true ); - $t = $this->getContext()->getLang()->time( $timestamp, true ); + $d = $this->getLang()->date( $timestamp, true ); + $t = $this->getLang()->time( $timestamp, true ); $s = ' ' . wfMsg( 'lastmodifiedat', $d, $t ); } else { $s = ''; @@ -1092,7 +1065,7 @@ abstract class Skin { function showEmailUser( $id ) { $targetUser = User::newFromId( $id ); - return $this->getContext()->getUser()->canSendEmail() && # the sending user must have a confirmed email address + return $this->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 } @@ -1214,7 +1187,7 @@ abstract class Skin { global $parserMemc, $wgEnableSidebarCache, $wgSidebarCacheExpiry; wfProfileIn( __METHOD__ ); - $key = wfMemcKey( 'sidebar', $this->getContext()->getLang()->getCode() ); + $key = wfMemcKey( 'sidebar', $this->getLang()->getCode() ); if ( $wgEnableSidebarCache ) { $cachedsidebar = $parserMemc->get( $key ); @@ -1350,9 +1323,9 @@ abstract class Skin { * @return MediaWiki message or if no new talk page messages, nothing */ function getNewtalks() { - $out = $this->getContext()->getOutput(); + $out = $this->getOutput(); - $newtalks = $this->getContext()->getUser()->getNewMessageLinks(); + $newtalks = $this->getUser()->getNewMessageLinks(); $ntl = ''; if ( count( $newtalks ) == 1 && $newtalks[0]['wiki'] === wfWikiID() ) { @@ -1360,7 +1333,7 @@ abstract class Skin { $userTalkTitle = $userTitle->getTalkPage(); if ( !$userTalkTitle->equals( $out->getTitle() ) ) { - $newMessagesLink = $this->link( + $newMessagesLink = Linker::link( $userTalkTitle, wfMsgHtml( 'newmessageslink' ), array(), @@ -1368,7 +1341,7 @@ abstract class Skin { array( 'known', 'noclasses' ) ); - $newMessagesDiffLink = $this->link( + $newMessagesDiffLink = Linker::link( $userTalkTitle, wfMsgHtml( 'newmessagesdifflink' ), array(), @@ -1447,7 +1420,7 @@ abstract class Skin { } if ( $needParse ) { - $parsed = $this->getContext()->getOutput()->parse( $notice ); + $parsed = $this->getOutput()->parse( $notice ); $parserMemc->set( $key, array( 'html' => $parsed, 'hash' => md5( $notice ) ), 600 ); $notice = $parsed; } @@ -1487,7 +1460,7 @@ abstract class Skin { $siteNotice = ''; if ( wfRunHooks( 'SiteNoticeBefore', array( &$siteNotice, $this ) ) ) { - if ( is_object( $this->getContext()->getUser() ) && $this->getContext()->getUser()->isLoggedIn() ) { + if ( $this->getUser() instanceof User && $this->getUser()->isLoggedIn() ) { $siteNotice = $this->getCachedNotice( 'sitenotice' ); } else { $anonNotice = $this->getCachedNotice( 'anonnotice' ); diff --git a/includes/SpecialPage.php b/includes/SpecialPage.php index 866cbecd5c..49dfc7dba4 100644 --- a/includes/SpecialPage.php +++ b/includes/SpecialPage.php @@ -27,7 +27,7 @@ * page list. * @ingroup SpecialPage */ -class SpecialPage { +class SpecialPage extends ContextSource { // The canonical name of this special page // Also used for the default

heading, @see getDescription() @@ -572,16 +572,6 @@ class SpecialPage { 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 @@ -590,54 +580,14 @@ class SpecialPage { * @since 1.18 */ public function getContext() { - if ( $this->mContext instanceof RequestContext ) { - return $this->mContext; + if ( parent::getContext() instanceof RequestContext ) { + return parent::getContext(); } 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