From 096f6e91fc76fd658e04609504f7a06ee28beed2 Mon Sep 17 00:00:00 2001 From: Kunal Mehta Date: Mon, 19 Sep 2016 16:27:03 -0700 Subject: [PATCH] Rewrite to avoid messing with global state The main goal of this rewrite is to not use or mess with any global state. The ParserGetVariableValueTs and ParserGetVariableValueVarCache hooks were replaced with setting the timestamp via ParserOptions::setTimestamp(). This also means that {{#time:...}} from ParserFunctions extension will correctly use the page's timestamp instead of the current one. Disabling tidy is also done using ParserOptions instead of changing global state. Change-Id: Ib2810aa5891c57831380a1a4718656cc09932b96 --- SpecialCiteThisPage.php | 178 +++++++++++++++++++++------------------- extension.json | 1 - i18n/en.json | 1 + i18n/qqq.json | 1 + 4 files changed, 94 insertions(+), 87 deletions(-) diff --git a/SpecialCiteThisPage.php b/SpecialCiteThisPage.php index 5e1cae97..03d5fcec 100644 --- a/SpecialCiteThisPage.php +++ b/SpecialCiteThisPage.php @@ -1,18 +1,17 @@ tags to - // be generated around the output of the CiteThisPageOutput - // class TODO FIXME. - $wgUseTidy = false; - $this->setHeaders(); $this->outputHeader(); @@ -23,8 +22,7 @@ class SpecialCiteThisPage extends SpecialPage { if ( $title && $title->exists() ) { $id = $this->getRequest()->getInt( 'id' ); - $cout = new CiteThisPageOutput( $title, $id ); - $cout->execute(); + $this->showCitations( $title, $id ); } } @@ -84,54 +82,62 @@ class SpecialCiteThisPage extends SpecialPage { protected function getGroupName() { return 'pagetools'; } -} -class CiteThisPageOutput { - /** - * @var Title - */ - public $mTitle; + private function showCitations( Title $title, $revId ) { + if ( !$revId ) { + $revId = $title->getLatestRevID(); + } - /** - * @var Article - */ - public $mArticle; + $out = $this->getOutput(); - public $mId; + $revision = Revision::newFromTitle( $title, $revId ); + if ( !$revision ) { + $out->wrapWikiMsg( '
$1
', + [ 'citethispage-badrevision', $title->getPrefixedText(), $revId ] ); + return; + } - /** - * @var Parser - */ - public $mParser; + $parserOptions = $this->getParserOptions(); + // Set the overall timestamp to the revision's timestamp + $parserOptions->setTimestamp( $revision->getTimestamp() ); - /** - * @var ParserOptions - */ - public $mParserOptions; + $parser = $this->getParser(); + // Register our tag which just parses using a different + // context + $parser->setHook( 'citation', [ $this, 'citationTag' ] ); + // Also hold on to a separate Parser instance for tag parsing + // since we can't parse in a parse using the same Parser + $this->citationParser = $this->getParser(); - public $mSpTitle; + $ret = $parser->parse( + $this->getContentText(), + $title, + $parserOptions, + /* $linestart = */ false, + /* $clearstate = */ true, + $revId + ); - function __construct( $title, $id ) { - global $wgHooks, $wgParser; + $this->getOutput()->addModuleStyles( 'ext.citeThisPage' ); + $this->getOutput()->addParserOutputContent( $ret ); - $this->mTitle = $title; - $this->mArticle = new Article( $title ); - $this->mId = $id; - - $wgHooks['ParserGetVariableValueVarCache'][] = [ $this, 'varCache' ]; - - $this->genParserOptions(); - $this->genParser(); - - $wgParser->setHook( 'citation', [ $this, 'citationTagParse' ] ); } - function execute() { - global $wgOut, $wgParser, $wgHooks; + /** + * @return Parser + */ + private function getParser() { + $parserConf = $this->getConfig()->get( 'ParserConf' ); + return new $parserConf['class']( $parserConf ); + } - $wgHooks['ParserGetVariableValueTs'][] = [ $this, 'timestamp' ]; - - $msg = wfMessage( 'citethispage-content' )->inContentLanguage()->plain(); + /** + * Get the content to parse + * + * @return string + */ + private function getContentText() { + $msg = $this->msg( 'citethispage-content' )->inContentLanguage()->plain(); if ( $msg == '' ) { # With MediaWiki 1.20 the plain text files were deleted # and the text moved into SpecialCite.i18n.php @@ -146,49 +152,49 @@ class CiteThisPageOutput { $msg = file_get_contents( "${dir}citethispage-content" ); } } - $ret = $wgParser->parse( - $msg, $this->mTitle, $this->mParserOptions, false, true, $this->getRevId() + + return $msg; + } + + /** + * Get the common ParserOptions for both parses + * + * @return ParserOptions + */ + private function getParserOptions() { + $parserOptions = ParserOptions::newFromUser( $this->getUser() ); + $parserOptions->setDateFormat( 'default' ); + $parserOptions->setEditSection( false ); + + // Having tidy on causes whitespace and
 tags to
+		// be generated around the output of the CiteThisPageOutput
+		// class TODO FIXME.
+		$parserOptions->setTidy( false );
+
+		return $parserOptions;
+	}
+
+	/**
+	 * Implements the  tag.
+	 *
+	 * This is a hack to allow content that is typically parsed
+	 * using the page's timestamp/pagetitle to use the current
+	 * request's time and title
+	 *
+	 * @param string $text
+	 * @param array $params
+	 * @param Parser $parser
+	 * @return string
+	 */
+	public function citationTag( $text, $params, Parser $parser ) {
+		$ret = $this->citationParser->parse(
+			$text,
+			$this->getPageTitle(),
+			$this->getParserOptions(),
+			/* $linestart = */ false
 		);
-		$wgOut->addModuleStyles( 'ext.citeThisPage' );
-
-		$wgOut->addParserOutputContent( $ret );
-	}
-
-	function genParserOptions() {
-		global $wgUser;
-		$this->mParserOptions = ParserOptions::newFromUser( $wgUser );
-		$this->mParserOptions->setDateFormat( 'default' );
-		$this->mParserOptions->setEditSection( false );
-	}
-
-	function genParser() {
-		$this->mParser = new Parser;
-		$this->mSpTitle = SpecialPage::getTitleFor( 'CiteThisPage' );
-	}
-
-	function citationTagParse( $in, $argv ) {
-		$ret = $this->mParser->parse( $in, $this->mSpTitle, $this->mParserOptions, false );
 
 		return $ret->getText();
-	}
 
-	function varCache() {
-		return false;
-	}
-
-	function timestamp( &$parser, &$ts ) {
-		if ( isset( $parser->mTagHooks['citation'] ) ) {
-			$ts = wfTimestamp( TS_UNIX, $this->mArticle->getTimestamp() );
-		}
-
-		return true;
-	}
-
-	function getRevId() {
-		if ( $this->mId ) {
-			return $this->mId;
-		} else {
-			return $this->mTitle->getLatestRevID();
-		}
 	}
 }
diff --git a/extension.json b/extension.json
index 3a423ab6..e02d812b 100644
--- a/extension.json
+++ b/extension.json
@@ -37,7 +37,6 @@
 	},
 	"AutoloadClasses": {
 		"SpecialCiteThisPage": "SpecialCiteThisPage.php",
-		"CiteThisPageOutput": "SpecialCiteThisPage.php",
 		"CiteThisPageHooks": "CiteThisPage.hooks.php"
 	},
 	"manifest_version": 1
diff --git a/i18n/en.json b/i18n/en.json
index 56deb4e8..83133374 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -10,5 +10,6 @@
 	"citethispage-summary": "",
 	"citethispage-change-submit": "Cite",
 	"citethispage-change-target": "Page:",
+	"citethispage-badrevision": "Error: could not find any revision for the page \"$1\" with the revision ID $2.",
 	"citethispage-content": "__NOTOC__\n
\n\n== Bibliographic details for {{FULLPAGENAME}} ==\n\n* Page name: {{FULLPAGENAME}}\n* Author: {{SITENAME}} contributors\n* Publisher: ''{{SITENAME}}, {{int:sitesubtitle}}''.\n* Date of last revision: {{CURRENTDAY}} {{CURRENTMONTHNAME}} {{CURRENTYEAR}} {{CURRENTTIME}} UTC\n* Date retrieved: {{CURRENTDAY}} {{CURRENTMONTHNAME}} {{CURRENTYEAR}} {{CURRENTTIME}} UTC\n* Permanent URL: {{canonicalurl:{{FULLPAGENAME}}|oldid={{REVISIONID}}}}\n* Page Version ID: {{REVISIONID}}\n\n
\n " } diff --git a/i18n/qqq.json b/i18n/qqq.json index e374d169..1606f08a 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -18,5 +18,6 @@ "citethispage-summary": "{{notranslate}}\n\nA description message shown beneath the title of the Special page to explain what the point of the page is; generally un-used.", "citethispage-change-submit": "A button for users to change the page for which they will see a cite. See also {{msg-mw|citethispage-change-target}}.\n\n{{Identical|Cite}}", "citethispage-change-target": "A prompt for users to change the page for which they wish to see a cite. See also {{msg-mw|citethispage-change-submit}}.\n\n{{Identical|Page}}", + "citethispage-badrevision": "Error message if the title and/or revision ID cannot be found in the database", "citethispage-content": "Refers to {{msg-mw|Sitesubtitle}}.\n\n* This message is the entire text for the page Special:Cite\n* Any wikilinks in this message point to pages on the local wiki, so they must be translated.\n* Do not translate magic words like CURRENTYEAR, SITENAME etc.\n* Do not translate the parameter names (author, title etc.) for BibTeX entries.\n* Do not translate the div class plainlinks mw-specialCiteThisPage-styles." }