summaryrefslogtreecommitdiff
path: root/includes/parser
diff options
context:
space:
mode:
authorPierre Schmitz <pierre@archlinux.de>2014-12-27 15:41:37 +0100
committerPierre Schmitz <pierre@archlinux.de>2014-12-31 11:43:28 +0100
commitc1f9b1f7b1b77776192048005dcc66dcf3df2bfb (patch)
tree2b38796e738dd74cb42ecd9bfd151803108386bc /includes/parser
parentb88ab0086858470dd1f644e64cb4e4f62bb2be9b (diff)
Update to MediaWiki 1.24.1
Diffstat (limited to 'includes/parser')
-rw-r--r--includes/parser/CacheTime.php98
-rw-r--r--includes/parser/CoreParserFunctions.php710
-rw-r--r--includes/parser/CoreTagHooks.php26
-rw-r--r--includes/parser/DateFormatter.php51
-rw-r--r--includes/parser/LinkHolderArray.php243
-rw-r--r--includes/parser/MWTidy.php (renamed from includes/parser/Tidy.php)37
-rw-r--r--includes/parser/Parser.php1364
-rw-r--r--includes/parser/ParserCache.php108
-rw-r--r--includes/parser/ParserDiffTest.php (renamed from includes/parser/Parser_DiffTest.php)26
-rw-r--r--includes/parser/ParserOptions.php517
-rw-r--r--includes/parser/ParserOutput.php449
-rw-r--r--includes/parser/Preprocessor.php176
-rw-r--r--includes/parser/Preprocessor_DOM.php485
-rw-r--r--includes/parser/Preprocessor_Hash.php620
-rw-r--r--includes/parser/StripState.php58
15 files changed, 3275 insertions, 1693 deletions
diff --git a/includes/parser/CacheTime.php b/includes/parser/CacheTime.php
index 8190a8a0..94abc266 100644
--- a/includes/parser/CacheTime.php
+++ b/includes/parser/CacheTime.php
@@ -27,24 +27,64 @@
* @ingroup Parser
*/
class CacheTime {
+ /** @var array|bool ParserOptions which have been taken into account to
+ * produce output or false if not available.
+ */
+ public $mUsedOptions;
- var $mVersion = Parser::VERSION, # Compatibility check
+ public $mVersion = Parser::VERSION, # Compatibility check
$mCacheTime = '', # Time when this object was generated, or -1 for uncacheable. Used in ParserCache.
$mCacheExpiry = null, # Seconds after which the object should expire, use 0 for uncachable. Used in ParserCache.
- $mContainsOldMagic; # Boolean variable indicating if the input contained variables like {{CURRENTDAY}}
+ $mContainsOldMagic, # Boolean variable indicating if the input contained variables like {{CURRENTDAY}}
+ $mCacheRevisionId = null; # Revision ID that was parsed
- function getCacheTime() { return $this->mCacheTime; }
+ /**
+ * @return string TS_MW timestamp
+ */
+ public function getCacheTime() {
+ return wfTimestamp( TS_MW, $this->mCacheTime );
+ }
- function containsOldMagic() { return $this->mContainsOldMagic; }
- function setContainsOldMagic( $com ) { return wfSetVar( $this->mContainsOldMagic, $com ); }
+ /**
+ * @return bool
+ */
+ public function containsOldMagic() {
+ return $this->mContainsOldMagic;
+ }
+
+ /**
+ * @param bool $com
+ * @return bool
+ */
+ public function setContainsOldMagic( $com ) {
+ return wfSetVar( $this->mContainsOldMagic, $com );
+ }
/**
* setCacheTime() sets the timestamp expressing when the page has been rendered.
- * This doesn not control expiry, see updateCacheExpiry() for that!
- * @param $t string
+ * This does not control expiry, see updateCacheExpiry() for that!
+ * @param string $t
* @return string
*/
- function setCacheTime( $t ) { return wfSetVar( $this->mCacheTime, $t ); }
+ public function setCacheTime( $t ) {
+ return wfSetVar( $this->mCacheTime, $t );
+ }
+
+ /**
+ * @since 1.23
+ * @return int|null Revision id, if any was set
+ */
+ public function getCacheRevisionId() {
+ return $this->mCacheRevisionId;
+ }
+
+ /**
+ * @since 1.23
+ * @param int $id Revision id
+ */
+ public function setCacheRevisionId( $id ) {
+ $this->mCacheRevisionId = $id;
+ }
/**
* Sets the number of seconds after which this object should expire.
@@ -54,9 +94,9 @@ class CacheTime {
* or equal to the smallest number that was provided as an argument to
* updateCacheExpiry().
*
- * @param $seconds number
+ * @param int $seconds
*/
- function updateCacheExpiry( $seconds ) {
+ public function updateCacheExpiry( $seconds ) {
$seconds = (int)$seconds;
if ( $this->mCacheExpiry === null || $this->mCacheExpiry > $seconds ) {
@@ -78,7 +118,7 @@ class CacheTime {
* value of $wgParserCacheExpireTime.
* @return int|mixed|null
*/
- function getCacheExpiry() {
+ public function getCacheExpiry() {
global $wgParserCacheExpireTime;
if ( $this->mCacheTime < 0 ) {
@@ -107,7 +147,7 @@ class CacheTime {
/**
* @return bool
*/
- function isCacheable() {
+ public function isCacheable() {
return $this->getCacheExpiry() > 0;
}
@@ -116,17 +156,35 @@ class CacheTime {
* per-article cache invalidation timestamps, or if it comes from
* an incompatible older version.
*
- * @param string $touched the affected article's last touched timestamp
- * @return Boolean
+ * @param string $touched The affected article's last touched timestamp
+ * @return bool
*/
public function expired( $touched ) {
global $wgCacheEpoch;
- return !$this->isCacheable() || // parser says it's uncacheable
- $this->getCacheTime() < $touched ||
- $this->getCacheTime() <= $wgCacheEpoch ||
- $this->getCacheTime() < wfTimestamp( TS_MW, time() - $this->getCacheExpiry() ) || // expiry period has passed
- !isset( $this->mVersion ) ||
- version_compare( $this->mVersion, Parser::VERSION, "lt" );
+
+ return !$this->isCacheable() // parser says it's uncacheable
+ || $this->getCacheTime() < $touched
+ || $this->getCacheTime() <= $wgCacheEpoch
+ || $this->getCacheTime() <
+ wfTimestamp( TS_MW, time() - $this->getCacheExpiry() ) // expiry period has passed
+ || !isset( $this->mVersion )
+ || version_compare( $this->mVersion, Parser::VERSION, "lt" );
}
+ /**
+ * Return true if this cached output object is for a different revision of
+ * the page.
+ *
+ * @todo We always return false if $this->getCacheRevisionId() is null;
+ * this prevents invalidating the whole parser cache when this change is
+ * deployed. Someday that should probably be changed.
+ *
+ * @since 1.23
+ * @param int $id The affected article's current revision id
+ * @return bool
+ */
+ public function isDifferentRevision( $id ) {
+ $cached = $this->getCacheRevisionId();
+ return $cached !== null && $id !== $cached;
+ }
}
diff --git a/includes/parser/CoreParserFunctions.php b/includes/parser/CoreParserFunctions.php
index 4b6eeca2..eacbecd4 100644
--- a/includes/parser/CoreParserFunctions.php
+++ b/includes/parser/CoreParserFunctions.php
@@ -27,97 +27,69 @@
*/
class CoreParserFunctions {
/**
- * @param $parser Parser
+ * @param Parser $parser
* @return void
*/
- static function register( $parser ) {
+ public static function register( $parser ) {
global $wgAllowDisplayTitle, $wgAllowSlowParserFunctions;
- # Syntax for arguments (see self::setFunctionHook):
+ # Syntax for arguments (see Parser::setFunctionHook):
# "name for lookup in localized magic words array",
# function callback,
# optional SFH_NO_HASH to omit the hash from calls (e.g. {{int:...}}
# instead of {{#int:...}})
+ $noHashFunctions = array(
+ 'ns', 'nse', 'urlencode', 'lcfirst', 'ucfirst', 'lc', 'uc',
+ 'localurl', 'localurle', 'fullurl', 'fullurle', 'canonicalurl',
+ 'canonicalurle', 'formatnum', 'grammar', 'gender', 'plural',
+ 'numberofpages', 'numberofusers', 'numberofactiveusers',
+ 'numberofarticles', 'numberoffiles', 'numberofadmins',
+ 'numberingroup', 'numberofedits', 'numberofviews', 'language',
+ 'padleft', 'padright', 'anchorencode', 'defaultsort', 'filepath',
+ 'pagesincategory', 'pagesize', 'protectionlevel',
+ 'namespacee', 'namespacenumber', 'talkspace', 'talkspacee',
+ 'subjectspace', 'subjectspacee', 'pagename', 'pagenamee',
+ 'fullpagename', 'fullpagenamee', 'rootpagename', 'rootpagenamee',
+ 'basepagename', 'basepagenamee', 'subpagename', 'subpagenamee',
+ 'talkpagename', 'talkpagenamee', 'subjectpagename',
+ 'subjectpagenamee', 'pageid', 'revisionid', 'revisionday',
+ 'revisionday2', 'revisionmonth', 'revisionmonth1', 'revisionyear',
+ 'revisiontimestamp', 'revisionuser', 'cascadingsources',
+ );
+ foreach ( $noHashFunctions as $func ) {
+ $parser->setFunctionHook( $func, array( __CLASS__, $func ), SFH_NO_HASH );
+ }
- $parser->setFunctionHook( 'int', array( __CLASS__, 'intFunction' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'ns', array( __CLASS__, 'ns' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'nse', array( __CLASS__, 'nse' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'urlencode', array( __CLASS__, 'urlencode' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'lcfirst', array( __CLASS__, 'lcfirst' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'ucfirst', array( __CLASS__, 'ucfirst' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'lc', array( __CLASS__, 'lc' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'uc', array( __CLASS__, 'uc' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'localurl', array( __CLASS__, 'localurl' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'localurle', array( __CLASS__, 'localurle' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'fullurl', array( __CLASS__, 'fullurl' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'fullurle', array( __CLASS__, 'fullurle' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'canonicalurl', array( __CLASS__, 'canonicalurl' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'canonicalurle', array( __CLASS__, 'canonicalurle' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'formatnum', array( __CLASS__, 'formatnum' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'grammar', array( __CLASS__, 'grammar' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'gender', array( __CLASS__, 'gender' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'plural', array( __CLASS__, 'plural' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'numberofpages', array( __CLASS__, 'numberofpages' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'numberofusers', array( __CLASS__, 'numberofusers' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'numberofactiveusers', array( __CLASS__, 'numberofactiveusers' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'numberofarticles', array( __CLASS__, 'numberofarticles' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'numberoffiles', array( __CLASS__, 'numberoffiles' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'numberofadmins', array( __CLASS__, 'numberofadmins' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'numberingroup', array( __CLASS__, 'numberingroup' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'numberofedits', array( __CLASS__, 'numberofedits' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'numberofviews', array( __CLASS__, 'numberofviews' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'language', array( __CLASS__, 'language' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'padleft', array( __CLASS__, 'padleft' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'padright', array( __CLASS__, 'padright' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'anchorencode', array( __CLASS__, 'anchorencode' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'special', array( __CLASS__, 'special' ) );
- $parser->setFunctionHook( 'speciale', array( __CLASS__, 'speciale' ) );
- $parser->setFunctionHook( 'defaultsort', array( __CLASS__, 'defaultsort' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'filepath', array( __CLASS__, 'filepath' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'pagesincategory', array( __CLASS__, 'pagesincategory' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'pagesize', array( __CLASS__, 'pagesize' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'protectionlevel', array( __CLASS__, 'protectionlevel' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'namespace', array( __CLASS__, 'mwnamespace' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'namespacee', array( __CLASS__, 'namespacee' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'namespacenumber', array( __CLASS__, 'namespacenumber' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'talkspace', array( __CLASS__, 'talkspace' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'talkspacee', array( __CLASS__, 'talkspacee' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'subjectspace', array( __CLASS__, 'subjectspace' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'subjectspacee', array( __CLASS__, 'subjectspacee' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'pagename', array( __CLASS__, 'pagename' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'pagenamee', array( __CLASS__, 'pagenamee' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'fullpagename', array( __CLASS__, 'fullpagename' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'fullpagenamee', array( __CLASS__, 'fullpagenamee' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'rootpagename', array( __CLASS__, 'rootpagename' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'rootpagenamee', array( __CLASS__, 'rootpagenamee' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'basepagename', array( __CLASS__, 'basepagename' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'basepagenamee', array( __CLASS__, 'basepagenamee' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'subpagename', array( __CLASS__, 'subpagename' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'subpagenamee', array( __CLASS__, 'subpagenamee' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'talkpagename', array( __CLASS__, 'talkpagename' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'talkpagenamee', array( __CLASS__, 'talkpagenamee' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'subjectpagename', array( __CLASS__, 'subjectpagename' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'subjectpagenamee', array( __CLASS__, 'subjectpagenamee' ), SFH_NO_HASH );
- $parser->setFunctionHook( 'tag', array( __CLASS__, 'tagObj' ), SFH_OBJECT_ARGS );
- $parser->setFunctionHook( 'formatdate', array( __CLASS__, 'formatDate' ) );
+ $parser->setFunctionHook( 'namespace', array( __CLASS__, 'mwnamespace' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'int', array( __CLASS__, 'intFunction' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'special', array( __CLASS__, 'special' ) );
+ $parser->setFunctionHook( 'speciale', array( __CLASS__, 'speciale' ) );
+ $parser->setFunctionHook( 'tag', array( __CLASS__, 'tagObj' ), SFH_OBJECT_ARGS );
+ $parser->setFunctionHook( 'formatdate', array( __CLASS__, 'formatDate' ) );
if ( $wgAllowDisplayTitle ) {
$parser->setFunctionHook( 'displaytitle', array( __CLASS__, 'displaytitle' ), SFH_NO_HASH );
}
if ( $wgAllowSlowParserFunctions ) {
- $parser->setFunctionHook( 'pagesinnamespace', array( __CLASS__, 'pagesinnamespace' ), SFH_NO_HASH );
+ $parser->setFunctionHook(
+ 'pagesinnamespace',
+ array( __CLASS__, 'pagesinnamespace' ),
+ SFH_NO_HASH
+ );
}
}
/**
- * @param $parser Parser
+ * @param Parser $parser
* @param string $part1
* @return array
*/
- static function intFunction( $parser, $part1 = '' /*, ... */ ) {
+ public static function intFunction( $parser, $part1 = '' /*, ... */ ) {
if ( strval( $part1 ) !== '' ) {
$args = array_slice( func_get_args(), 2 );
- $message = wfMessage( $part1, $args )->inLanguage( $parser->getOptions()->getUserLangObj() )->plain();
+ $message = wfMessage( $part1, $args )
+ ->inLanguage( $parser->getOptions()->getUserLangObj() )->plain();
+
return array( $message, 'noparse' => false );
} else {
return array( 'found' => false );
@@ -125,12 +97,13 @@ class CoreParserFunctions {
}
/**
- * @param $parser Parser
- * @param $date
- * @param null $defaultPref
- * @return mixed|string
+ * @param Parser $parser
+ * @param string $date
+ * @param string $defaultPref
+ *
+ * @return string
*/
- static function formatDate( $parser, $date, $defaultPref = null ) {
+ public static function formatDate( $parser, $date, $defaultPref = null ) {
$lang = $parser->getFunctionLang();
$df = DateFormatter::getInstance( $lang );
@@ -148,7 +121,7 @@ class CoreParserFunctions {
return $date;
}
- static function ns( $parser, $part1 = '' ) {
+ public static function ns( $parser, $part1 = '' ) {
global $wgContLang;
if ( intval( $part1 ) || $part1 == "0" ) {
$index = intval( $part1 );
@@ -162,7 +135,7 @@ class CoreParserFunctions {
}
}
- static function nse( $parser, $part1 = '' ) {
+ public static function nse( $parser, $part1 = '' ) {
$ret = self::ns( $parser, $part1 );
if ( is_string( $ret ) ) {
$ret = wfUrlencode( str_replace( ' ', '_', $ret ) );
@@ -177,12 +150,12 @@ class CoreParserFunctions {
* Or to encode a value for the HTTP "path", spaces are encoded as '%20'.
* For links to "wiki"s, or similar software, spaces are encoded as '_',
*
- * @param $parser Parser object
+ * @param Parser $parser
* @param string $s The text to encode.
* @param string $arg (optional): The type of encoding.
* @return string
*/
- static function urlencode( $parser, $s = '', $arg = null ) {
+ public static function urlencode( $parser, $s = '', $arg = null ) {
static $magicWords = null;
if ( is_null( $magicWords ) ) {
$magicWords = new MagicWordArray( array( 'url_path', 'url_query', 'url_wiki' ) );
@@ -208,44 +181,76 @@ class CoreParserFunctions {
return $parser->markerSkipCallback( $s, $func );
}
- static function lcfirst( $parser, $s = '' ) {
+ public static function lcfirst( $parser, $s = '' ) {
global $wgContLang;
return $wgContLang->lcfirst( $s );
}
- static function ucfirst( $parser, $s = '' ) {
+ public static function ucfirst( $parser, $s = '' ) {
global $wgContLang;
return $wgContLang->ucfirst( $s );
}
/**
- * @param $parser Parser
+ * @param Parser $parser
* @param string $s
- * @return
+ * @return string
*/
- static function lc( $parser, $s = '' ) {
+ public static function lc( $parser, $s = '' ) {
global $wgContLang;
return $parser->markerSkipCallback( $s, array( $wgContLang, 'lc' ) );
}
/**
- * @param $parser Parser
+ * @param Parser $parser
* @param string $s
- * @return
+ * @return string
*/
- static function uc( $parser, $s = '' ) {
+ public static function uc( $parser, $s = '' ) {
global $wgContLang;
return $parser->markerSkipCallback( $s, array( $wgContLang, 'uc' ) );
}
- static function localurl( $parser, $s = '', $arg = null ) { return self::urlFunction( 'getLocalURL', $s, $arg ); }
- static function localurle( $parser, $s = '', $arg = null ) { return self::urlFunction( 'escapeLocalURL', $s, $arg ); }
- static function fullurl( $parser, $s = '', $arg = null ) { return self::urlFunction( 'getFullURL', $s, $arg ); }
- static function fullurle( $parser, $s = '', $arg = null ) { return self::urlFunction( 'escapeFullURL', $s, $arg ); }
- static function canonicalurl( $parser, $s = '', $arg = null ) { return self::urlFunction( 'getCanonicalURL', $s, $arg ); }
- static function canonicalurle( $parser, $s = '', $arg = null ) { return self::urlFunction( 'escapeCanonicalURL', $s, $arg ); }
+ public static function localurl( $parser, $s = '', $arg = null ) {
+ return self::urlFunction( 'getLocalURL', $s, $arg );
+ }
+
+ public static function localurle( $parser, $s = '', $arg = null ) {
+ $temp = self::urlFunction( 'getLocalURL', $s, $arg );
+ if ( !is_string( $temp ) ) {
+ return $temp;
+ } else {
+ return htmlspecialchars( $temp );
+ }
+ }
+
+ public static function fullurl( $parser, $s = '', $arg = null ) {
+ return self::urlFunction( 'getFullURL', $s, $arg );
+ }
+
+ public static function fullurle( $parser, $s = '', $arg = null ) {
+ $temp = self::urlFunction( 'getFullURL', $s, $arg );
+ if ( !is_string( $temp ) ) {
+ return $temp;
+ } else {
+ return htmlspecialchars( $temp );
+ }
+ }
+
+ public static function canonicalurl( $parser, $s = '', $arg = null ) {
+ return self::urlFunction( 'getCanonicalURL', $s, $arg );
+ }
- static function urlFunction( $func, $s = '', $arg = null ) {
+ public static function canonicalurle( $parser, $s = '', $arg = null ) {
+ $temp = self::urlFunction( 'getCanonicalURL', $s, $arg );
+ if ( !is_string( $temp ) ) {
+ return $temp;
+ } else {
+ return htmlspecialchars( $temp );
+ }
+ }
+
+ public static function urlFunction( $func, $s = '', $arg = null ) {
$title = Title::newFromText( $s );
# Due to order of execution of a lot of bits, the values might be encoded
# before arriving here; if that's true, then the title can't be created
@@ -271,12 +276,12 @@ class CoreParserFunctions {
}
/**
- * @param $parser Parser
+ * @param Parser $parser
* @param string $num
* @param string $arg
* @return string
*/
- static function formatnum( $parser, $num = '', $arg = null ) {
+ public static function formatnum( $parser, $num = '', $arg = null ) {
if ( self::matchAgainstMagicword( 'rawsuffix', $arg ) ) {
$func = array( $parser->getFunctionLang(), 'parseFormattedNumber' );
} elseif ( self::matchAgainstMagicword( 'nocommafysuffix', $arg ) ) {
@@ -288,22 +293,22 @@ class CoreParserFunctions {
}
/**
- * @param $parser Parser
+ * @param Parser $parser
* @param string $case
* @param string $word
- * @return
+ * @return string
*/
- static function grammar( $parser, $case = '', $word = '' ) {
+ public static function grammar( $parser, $case = '', $word = '' ) {
$word = $parser->killMarkers( $word );
return $parser->getFunctionLang()->convertGrammar( $word, $case );
}
/**
- * @param $parser Parser
- * @param $username string
- * @return
+ * @param Parser $parser
+ * @param string $username
+ * @return string
*/
- static function gender( $parser, $username ) {
+ public static function gender( $parser, $username ) {
wfProfileIn( __METHOD__ );
$forms = array_slice( func_get_args(), 2 );
@@ -341,11 +346,11 @@ class CoreParserFunctions {
}
/**
- * @param $parser Parser
+ * @param Parser $parser
* @param string $text
- * @return
+ * @return string
*/
- static function plural( $parser, $text = '' ) {
+ public static function plural( $parser, $text = '' ) {
$forms = array_slice( func_get_args(), 2 );
$text = $parser->getFunctionLang()->parseFormattedNumber( $text );
settype( $text, ctype_digit( $text ) ? 'int' : 'float' );
@@ -356,13 +361,20 @@ class CoreParserFunctions {
* Override the title of the page when viewed, provided we've been given a
* title which will normalise to the canonical title
*
- * @param $parser Parser: parent parser
- * @param string $text desired title text
- * @return String
+ * @param Parser $parser Parent parser
+ * @param string $text Desired title text
+ * @param string $uarg
+ * @return string
*/
- static function displaytitle( $parser, $text = '' ) {
+ public static function displaytitle( $parser, $text = '', $uarg = '' ) {
global $wgRestrictDisplayTitle;
+ static $magicWords = null;
+ if ( is_null( $magicWords ) ) {
+ $magicWords = new MagicWordArray( array( 'displaytitle_noerror', 'displaytitle_noreplace' ) );
+ }
+ $arg = $magicWords->matchStartToEnd( $uarg );
+
// parse a limited subset of wiki markup (just the single quote items)
$text = $parser->doQuotes( $text );
@@ -373,7 +385,7 @@ class CoreParserFunctions {
// list of disallowed tags for DISPLAYTITLE
// these will be escaped even though they are allowed in normal wiki text
$bad = array( 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'blockquote', 'ol', 'ul', 'li', 'hr',
- 'table', 'tr', 'th', 'td', 'dl', 'dd', 'caption', 'p', 'ruby', 'rb', 'rt', 'rp', 'br' );
+ 'table', 'tr', 'th', 'td', 'dl', 'dd', 'caption', 'p', 'ruby', 'rb', 'rt', 'rtc', 'rp', 'br' );
// disallow some styles that could be used to bypass $wgRestrictDisplayTitle
if ( $wgRestrictDisplayTitle ) {
@@ -399,13 +411,34 @@ class CoreParserFunctions {
// only requested titles that normalize to the actual title are allowed through
// if $wgRestrictDisplayTitle is true (it is by default)
// mimic the escaping process that occurs in OutputPage::setPageTitle
- $text = Sanitizer::normalizeCharReferences( Sanitizer::removeHTMLtags( $text, $htmlTagsCallback, array(), array(), $bad ) );
+ $text = Sanitizer::normalizeCharReferences( Sanitizer::removeHTMLtags(
+ $text,
+ $htmlTagsCallback,
+ array(),
+ array(),
+ $bad
+ ) );
$title = Title::newFromText( Sanitizer::stripAllTags( $text ) );
- if ( !$wgRestrictDisplayTitle ) {
- $parser->mOutput->setDisplayTitle( $text );
- } elseif ( $title instanceof Title && $title->getFragment() == '' && $title->equals( $parser->mTitle ) ) {
- $parser->mOutput->setDisplayTitle( $text );
+ if ( !$wgRestrictDisplayTitle ||
+ ( $title instanceof Title
+ && !$title->hasFragment()
+ && $title->equals( $parser->mTitle ) )
+ ) {
+ $old = $parser->mOutput->getProperty( 'displaytitle' );
+ if ( $old === false || $arg !== 'displaytitle_noreplace' ) {
+ $parser->mOutput->setDisplayTitle( $text );
+ }
+ if ( $old !== false && $old !== $text && !$arg ) {
+ $converter = $parser->getConverterLanguage()->getConverter();
+ return '<span class="error">' .
+ wfMessage( 'duplicate-displaytitle',
+ // Message should be parsed, but these params should only be escaped.
+ $converter->markNoConversion( wfEscapeWikiText( $old ) ),
+ $converter->markNoConversion( wfEscapeWikiText( $text ) )
+ )->inContentLanguage()->text() .
+ '</span>';
+ }
}
return '';
@@ -414,19 +447,20 @@ class CoreParserFunctions {
/**
* Matches the given value against the value of given magic word
*
- * @param string $magicword magic word key
- * @param mixed $value value to match
- * @return boolean true on successful match
+ * @param string $magicword Magic word key
+ * @param string $value Value to match
+ * @return bool True on successful match
*/
- static private function matchAgainstMagicword( $magicword, $value ) {
- if ( strval( $value ) === '' ) {
+ private static function matchAgainstMagicword( $magicword, $value ) {
+ $value = trim( strval( $value ) );
+ if ( $value === '' ) {
return false;
}
$mwObject = MagicWord::get( $magicword );
- return $mwObject->match( $value );
+ return $mwObject->matchStartToEnd( $value );
}
- static function formatRaw( $num, $raw ) {
+ public static function formatRaw( $num, $raw ) {
if ( self::matchAgainstMagicword( 'rawsuffix', $raw ) ) {
return $num;
} else {
@@ -434,35 +468,35 @@ class CoreParserFunctions {
return $wgContLang->formatNum( $num );
}
}
- static function numberofpages( $parser, $raw = null ) {
+ public static function numberofpages( $parser, $raw = null ) {
return self::formatRaw( SiteStats::pages(), $raw );
}
- static function numberofusers( $parser, $raw = null ) {
+ public static function numberofusers( $parser, $raw = null ) {
return self::formatRaw( SiteStats::users(), $raw );
}
- static function numberofactiveusers( $parser, $raw = null ) {
+ public static function numberofactiveusers( $parser, $raw = null ) {
return self::formatRaw( SiteStats::activeUsers(), $raw );
}
- static function numberofarticles( $parser, $raw = null ) {
+ public static function numberofarticles( $parser, $raw = null ) {
return self::formatRaw( SiteStats::articles(), $raw );
}
- static function numberoffiles( $parser, $raw = null ) {
+ public static function numberoffiles( $parser, $raw = null ) {
return self::formatRaw( SiteStats::images(), $raw );
}
- static function numberofadmins( $parser, $raw = null ) {
+ public static function numberofadmins( $parser, $raw = null ) {
return self::formatRaw( SiteStats::numberingroup( 'sysop' ), $raw );
}
- static function numberofedits( $parser, $raw = null ) {
+ public static function numberofedits( $parser, $raw = null ) {
return self::formatRaw( SiteStats::edits(), $raw );
}
- static function numberofviews( $parser, $raw = null ) {
+ public static function numberofviews( $parser, $raw = null ) {
global $wgDisableCounters;
return !$wgDisableCounters ? self::formatRaw( SiteStats::views(), $raw ) : '';
}
- static function pagesinnamespace( $parser, $namespace = 0, $raw = null ) {
+ public static function pagesinnamespace( $parser, $namespace = 0, $raw = null ) {
return self::formatRaw( SiteStats::pagesInNs( intval( $namespace ) ), $raw );
}
- static function numberingroup( $parser, $name = '', $raw = null ) {
+ public static function numberingroup( $parser, $name = '', $raw = null ) {
return self::formatRaw( SiteStats::numberingroup( strtolower( $name ) ), $raw );
}
@@ -471,51 +505,53 @@ class CoreParserFunctions {
* corresponding magic word
* Note: function name changed to "mwnamespace" rather than "namespace"
* to not break PHP 5.3
+ * @param Parser $parser
+ * @param string $title
* @return mixed|string
*/
- static function mwnamespace( $parser, $title = null ) {
+ public static function mwnamespace( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) ) {
return '';
}
return str_replace( '_', ' ', $t->getNsText() );
}
- static function namespacee( $parser, $title = null ) {
+ public static function namespacee( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) ) {
return '';
}
return wfUrlencode( $t->getNsText() );
}
- static function namespacenumber( $parser, $title = null ) {
+ public static function namespacenumber( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) ) {
return '';
}
return $t->getNamespace();
}
- static function talkspace( $parser, $title = null ) {
+ public static function talkspace( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) || !$t->canTalk() ) {
return '';
}
return str_replace( '_', ' ', $t->getTalkNsText() );
}
- static function talkspacee( $parser, $title = null ) {
+ public static function talkspacee( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) || !$t->canTalk() ) {
return '';
}
return wfUrlencode( $t->getTalkNsText() );
}
- static function subjectspace( $parser, $title = null ) {
+ public static function subjectspace( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) ) {
return '';
}
return str_replace( '_', ' ', $t->getSubjectNsText() );
}
- static function subjectspacee( $parser, $title = null ) {
+ public static function subjectspacee( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) ) {
return '';
@@ -526,100 +562,102 @@ class CoreParserFunctions {
/**
* Functions to get and normalize pagenames, corresponding to the magic words
* of the same names
- * @return String
+ * @param Parser $parser
+ * @param string $title
+ * @return string
*/
- static function pagename( $parser, $title = null ) {
+ public static function pagename( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) ) {
return '';
}
return wfEscapeWikiText( $t->getText() );
}
- static function pagenamee( $parser, $title = null ) {
+ public static function pagenamee( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) ) {
return '';
}
return wfEscapeWikiText( $t->getPartialURL() );
}
- static function fullpagename( $parser, $title = null ) {
+ public static function fullpagename( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) || !$t->canTalk() ) {
return '';
}
return wfEscapeWikiText( $t->getPrefixedText() );
}
- static function fullpagenamee( $parser, $title = null ) {
+ public static function fullpagenamee( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) || !$t->canTalk() ) {
return '';
}
return wfEscapeWikiText( $t->getPrefixedURL() );
}
- static function subpagename( $parser, $title = null ) {
+ public static function subpagename( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) ) {
return '';
}
return wfEscapeWikiText( $t->getSubpageText() );
}
- static function subpagenamee( $parser, $title = null ) {
+ public static function subpagenamee( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) ) {
return '';
}
return wfEscapeWikiText( $t->getSubpageUrlForm() );
}
- static function rootpagename( $parser, $title = null ) {
+ public static function rootpagename( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) ) {
return '';
}
return wfEscapeWikiText( $t->getRootText() );
}
- static function rootpagenamee( $parser, $title = null ) {
+ public static function rootpagenamee( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) ) {
return '';
}
return wfEscapeWikiText( wfUrlEncode( str_replace( ' ', '_', $t->getRootText() ) ) );
}
- static function basepagename( $parser, $title = null ) {
+ public static function basepagename( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) ) {
return '';
}
return wfEscapeWikiText( $t->getBaseText() );
}
- static function basepagenamee( $parser, $title = null ) {
+ public static function basepagenamee( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) ) {
return '';
}
return wfEscapeWikiText( wfUrlEncode( str_replace( ' ', '_', $t->getBaseText() ) ) );
}
- static function talkpagename( $parser, $title = null ) {
+ public static function talkpagename( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) || !$t->canTalk() ) {
return '';
}
return wfEscapeWikiText( $t->getTalkPage()->getPrefixedText() );
}
- static function talkpagenamee( $parser, $title = null ) {
+ public static function talkpagenamee( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) || !$t->canTalk() ) {
return '';
}
return wfEscapeWikiText( $t->getTalkPage()->getPrefixedURL() );
}
- static function subjectpagename( $parser, $title = null ) {
+ public static function subjectpagename( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) ) {
return '';
}
return wfEscapeWikiText( $t->getSubjectPage()->getPrefixedText() );
}
- static function subjectpagenamee( $parser, $title = null ) {
+ public static function subjectpagenamee( $parser, $title = null ) {
$t = Title::newFromText( $title );
if ( is_null( $t ) ) {
return '';
@@ -631,9 +669,13 @@ class CoreParserFunctions {
* Return the number of pages, files or subcats in the given category,
* or 0 if it's nonexistent. This is an expensive parser function and
* can't be called too many times per page.
+ * @param Parser $parser
+ * @param string $name
+ * @param string $arg1
+ * @param string $arg2
* @return string
*/
- static function pagesincategory( $parser, $name = '', $arg1 = null, $arg2 = null ) {
+ public static function pagesincategory( $parser, $name = '', $arg1 = null, $arg2 = null ) {
global $wgContLang;
static $magicWords = null;
if ( is_null( $magicWords ) ) {
@@ -695,46 +737,29 @@ class CoreParserFunctions {
* Return the size of the given page, or 0 if it's nonexistent. This is an
* expensive parser function and can't be called too many times per page.
*
- * @todo FIXME: Title::getLength() documentation claims that it adds things
- * to the link cache, so the local cache here should be unnecessary, but
- * in fact calling getLength() repeatedly for the same $page does seem to
- * run one query for each call?
- * @todo Document parameters
- *
- * @param $parser Parser
- * @param $page String Name of page to check (Default: empty string)
- * @param $raw String Should number be human readable with commas or just number
+ * @param Parser $parser
+ * @param string $page Name of page to check (Default: empty string)
+ * @param string $raw Should number be human readable with commas or just number
* @return string
*/
- static function pagesize( $parser, $page = '', $raw = null ) {
- static $cache = array();
+ public static function pagesize( $parser, $page = '', $raw = null ) {
$title = Title::newFromText( $page );
if ( !is_object( $title ) ) {
- $cache[$page] = 0;
return self::formatRaw( 0, $raw );
}
- # Normalize name for cache
- $page = $title->getPrefixedText();
-
- $length = 0;
- if ( isset( $cache[$page] ) ) {
- $length = $cache[$page];
- } elseif ( $parser->incrementExpensiveFunctionCount() ) {
- $rev = Revision::newFromTitle( $title, false, Revision::READ_NORMAL );
- $pageID = $rev ? $rev->getPage() : 0;
- $revID = $rev ? $rev->getId() : 0;
- $length = $cache[$page] = $rev ? $rev->getSize() : 0;
-
- // Register dependency in templatelinks
- $parser->mOutput->addTemplate( $title, $pageID, $revID );
- }
+ // fetch revision from cache/database and return the value
+ $rev = self::getCachedRevisionObject( $parser, $title );
+ $length = $rev ? $rev->getSize() : 0;
return self::formatRaw( $length, $raw );
}
/**
- * Returns the requested protection level for the current page
+ * Returns the requested protection level for the current page. This
+ * is an expensive parser function and can't be called too many times
+ * per page, unless the protection levels for the given title have
+ * already been retrieved
*
* @param Parser $parser
* @param string $type
@@ -742,25 +767,28 @@ class CoreParserFunctions {
*
* @return string
*/
- static function protectionlevel( $parser, $type = '', $title = '' ) {
+ public static function protectionlevel( $parser, $type = '', $title = '' ) {
$titleObject = Title::newFromText( $title );
if ( !( $titleObject instanceof Title ) ) {
$titleObject = $parser->mTitle;
}
- $restrictions = $titleObject->getRestrictions( strtolower( $type ) );
- # Title::getRestrictions returns an array, its possible it may have
- # multiple values in the future
- return implode( $restrictions, ',' );
+ if ( $titleObject->areRestrictionsLoaded() || $parser->incrementExpensiveFunctionCount() ) {
+ $restrictions = $titleObject->getRestrictions( strtolower( $type ) );
+ # Title::getRestrictions returns an array, its possible it may have
+ # multiple values in the future
+ return implode( $restrictions, ',' );
+ }
+ return '';
}
/**
* Gives language names.
- * @param $parser Parser
- * @param string $code Language code (of which to get name)
- * @param string $inLanguage Language code (in which to get name)
- * @return String
+ * @param Parser $parser
+ * @param string $code Language code (of which to get name)
+ * @param string $inLanguage Language code (in which to get name)
+ * @return string
*/
- static function language( $parser, $code = '', $inLanguage = '' ) {
+ public static function language( $parser, $code = '', $inLanguage = '' ) {
$code = strtolower( $code );
$inLanguage = strtolower( $inLanguage );
$lang = Language::fetchLanguageName( $code, $inLanguage );
@@ -769,9 +797,14 @@ class CoreParserFunctions {
/**
* Unicode-safe str_pad with the restriction that $length is forced to be <= 500
+ * @param Parser $parser
+ * @param string $string
+ * @param int $length
+ * @param string $padding
+ * @param int $direction
* @return string
*/
- static function pad( $parser, $string, $length, $padding = '0', $direction = STR_PAD_RIGHT ) {
+ public static function pad( $parser, $string, $length, $padding = '0', $direction = STR_PAD_RIGHT ) {
$padding = $parser->killMarkers( $padding );
$lengthOfPadding = mb_strlen( $padding );
if ( $lengthOfPadding == 0 ) {
@@ -797,25 +830,25 @@ class CoreParserFunctions {
}
}
- static function padleft( $parser, $string = '', $length = 0, $padding = '0' ) {
+ public static function padleft( $parser, $string = '', $length = 0, $padding = '0' ) {
return self::pad( $parser, $string, $length, $padding, STR_PAD_LEFT );
}
- static function padright( $parser, $string = '', $length = 0, $padding = '0' ) {
+ public static function padright( $parser, $string = '', $length = 0, $padding = '0' ) {
return self::pad( $parser, $string, $length, $padding );
}
/**
- * @param $parser Parser
- * @param $text
+ * @param Parser $parser
+ * @param string $text
* @return string
*/
- static function anchorencode( $parser, $text ) {
+ public static function anchorencode( $parser, $text ) {
$text = $parser->killMarkers( $text );
return (string)substr( $parser->guessSectionNameFromWikiText( $text ), 1 );
}
- static function special( $parser, $text ) {
+ public static function special( $parser, $text ) {
list( $page, $subpage ) = SpecialPageFactory::resolveAlias( $text );
if ( $page ) {
$title = SpecialPage::getTitleFor( $page, $subpage );
@@ -827,12 +860,12 @@ class CoreParserFunctions {
}
}
- static function speciale( $parser, $text ) {
+ public static function speciale( $parser, $text ) {
return wfUrlencode( str_replace( ' ', '_', self::special( $parser, $text ) ) );
}
/**
- * @param $parser Parser
+ * @param Parser $parser
* @param string $text The sortkey to use
* @param string $uarg Either "noreplace" or "noerror" (in en)
* both suppress errors, and noreplace does nothing if
@@ -869,8 +902,9 @@ class CoreParserFunctions {
}
}
- // Usage {{filepath|300}}, {{filepath|nowiki}}, {{filepath|nowiki|300}} or {{filepath|300|nowiki}}
- // or {{filepath|300px}}, {{filepath|200x300px}}, {{filepath|nowiki|200x300px}}, {{filepath|200x300px|nowiki}}
+ // Usage {{filepath|300}}, {{filepath|nowiki}}, {{filepath|nowiki|300}}
+ // or {{filepath|300|nowiki}} or {{filepath|300px}}, {{filepath|200x300px}},
+ // {{filepath|nowiki|200x300px}}, {{filepath|200x300px|nowiki}}.
public static function filepath( $parser, $name = '', $argA = '', $argB = '' ) {
$file = wfFindFile( $name );
@@ -907,6 +941,9 @@ class CoreParserFunctions {
/**
* Parser function to extension tag adaptor
+ * @param Parser $parser
+ * @param PPFrame $frame
+ * @param array $args
* @return string
*/
public static function tagObj( $parser, $frame, $args ) {
@@ -949,4 +986,271 @@ class CoreParserFunctions {
);
return $parser->extensionSubstitution( $params, $frame );
}
+
+ /**
+ * Fetched the current revision of the given title and return this.
+ * Will increment the expensive function count and
+ * add a template link to get the value refreshed on changes.
+ * For a given title, which is equal to the current parser title,
+ * the revision object from the parser is used, when that is the current one
+ *
+ * @param Parser $parser
+ * @param Title $title
+ * @return Revision
+ * @since 1.23
+ */
+ private static function getCachedRevisionObject( $parser, $title = null ) {
+ static $cache = null;
+ if ( $cache == null ) {
+ $cache = new MapCacheLRU( 50 );
+ }
+
+ if ( is_null( $title ) ) {
+ return null;
+ }
+
+ // Use the revision from the parser itself, when param is the current page
+ // and the revision is the current one
+ if ( $title->equals( $parser->getTitle() ) ) {
+ $parserRev = $parser->getRevisionObject();
+ if ( $parserRev && $parserRev->isCurrent() ) {
+ // force reparse after edit with vary-revision flag
+ $parser->getOutput()->setFlag( 'vary-revision' );
+ wfDebug( __METHOD__ . ": use current revision from parser, setting vary-revision...\n" );
+ return $parserRev;
+ }
+ }
+
+ // Normalize name for cache
+ $page = $title->getPrefixedDBkey();
+
+ if ( $cache->has( $page ) ) { // cache contains null values
+ return $cache->get( $page );
+ }
+ if ( $parser->incrementExpensiveFunctionCount() ) {
+ $rev = Revision::newFromTitle( $title, false, Revision::READ_NORMAL );
+ $pageID = $rev ? $rev->getPage() : 0;
+ $revID = $rev ? $rev->getId() : 0;
+ $cache->set( $page, $rev ); // maybe null
+
+ // Register dependency in templatelinks
+ $parser->getOutput()->addTemplate( $title, $pageID, $revID );
+
+ return $rev;
+ }
+ $cache->set( $page, null );
+ return null;
+ }
+
+ /**
+ * Get the pageid of a specified page
+ * @param Parser $parser
+ * @param string $title Title to get the pageid from
+ * @return int|null|string
+ * @since 1.23
+ */
+ public static function pageid( $parser, $title = null ) {
+ $t = Title::newFromText( $title );
+ if ( is_null( $t ) ) {
+ return '';
+ }
+ // Use title from parser to have correct pageid after edit
+ if ( $t->equals( $parser->getTitle() ) ) {
+ $t = $parser->getTitle();
+ return $t->getArticleID();
+ }
+
+ // These can't have ids
+ if ( !$t->canExist() || $t->isExternal() ) {
+ return 0;
+ }
+
+ // Check the link cache, maybe something already looked it up.
+ $linkCache = LinkCache::singleton();
+ $pdbk = $t->getPrefixedDBkey();
+ $id = $linkCache->getGoodLinkID( $pdbk );
+ if ( $id != 0 ) {
+ $parser->mOutput->addLink( $t, $id );
+ return $id;
+ }
+ if ( $linkCache->isBadLink( $pdbk ) ) {
+ $parser->mOutput->addLink( $t, 0 );
+ return $id;
+ }
+
+ // We need to load it from the DB, so mark expensive
+ if ( $parser->incrementExpensiveFunctionCount() ) {
+ $id = $t->getArticleID();
+ $parser->mOutput->addLink( $t, $id );
+ return $id;
+ }
+ return null;
+ }
+
+ /**
+ * Get the id from the last revision of a specified page.
+ * @param Parser $parser
+ * @param string $title Title to get the id from
+ * @return int|null|string
+ * @since 1.23
+ */
+ public static function revisionid( $parser, $title = null ) {
+ $t = Title::newFromText( $title );
+ if ( is_null( $t ) ) {
+ return '';
+ }
+ // fetch revision from cache/database and return the value
+ $rev = self::getCachedRevisionObject( $parser, $t );
+ return $rev ? $rev->getId() : '';
+ }
+
+ /**
+ * Get the day from the last revision of a specified page.
+ * @param Parser $parser
+ * @param string $title Title to get the day from
+ * @return string
+ * @since 1.23
+ */
+ public static function revisionday( $parser, $title = null ) {
+ $t = Title::newFromText( $title );
+ if ( is_null( $t ) ) {
+ return '';
+ }
+ // fetch revision from cache/database and return the value
+ $rev = self::getCachedRevisionObject( $parser, $t );
+ return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'j' ) : '';
+ }
+
+ /**
+ * Get the day with leading zeros from the last revision of a specified page.
+ * @param Parser $parser
+ * @param string $title Title to get the day from
+ * @return string
+ * @since 1.23
+ */
+ public static function revisionday2( $parser, $title = null ) {
+ $t = Title::newFromText( $title );
+ if ( is_null( $t ) ) {
+ return '';
+ }
+ // fetch revision from cache/database and return the value
+ $rev = self::getCachedRevisionObject( $parser, $t );
+ return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'd' ) : '';
+ }
+
+ /**
+ * Get the month with leading zeros from the last revision of a specified page.
+ * @param Parser $parser
+ * @param string $title Title to get the month from
+ * @return string
+ * @since 1.23
+ */
+ public static function revisionmonth( $parser, $title = null ) {
+ $t = Title::newFromText( $title );
+ if ( is_null( $t ) ) {
+ return '';
+ }
+ // fetch revision from cache/database and return the value
+ $rev = self::getCachedRevisionObject( $parser, $t );
+ return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'm' ) : '';
+ }
+
+ /**
+ * Get the month from the last revision of a specified page.
+ * @param Parser $parser
+ * @param string $title Title to get the month from
+ * @return string
+ * @since 1.23
+ */
+ public static function revisionmonth1( $parser, $title = null ) {
+ $t = Title::newFromText( $title );
+ if ( is_null( $t ) ) {
+ return '';
+ }
+ // fetch revision from cache/database and return the value
+ $rev = self::getCachedRevisionObject( $parser, $t );
+ return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'n' ) : '';
+ }
+
+ /**
+ * Get the year from the last revision of a specified page.
+ * @param Parser $parser
+ * @param string $title Title to get the year from
+ * @return string
+ * @since 1.23
+ */
+ public static function revisionyear( $parser, $title = null ) {
+ $t = Title::newFromText( $title );
+ if ( is_null( $t ) ) {
+ return '';
+ }
+ // fetch revision from cache/database and return the value
+ $rev = self::getCachedRevisionObject( $parser, $t );
+ return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'Y' ) : '';
+ }
+
+ /**
+ * Get the timestamp from the last revision of a specified page.
+ * @param Parser $parser
+ * @param string $title Title to get the timestamp from
+ * @return string
+ * @since 1.23
+ */
+ public static function revisiontimestamp( $parser, $title = null ) {
+ $t = Title::newFromText( $title );
+ if ( is_null( $t ) ) {
+ return '';
+ }
+ // fetch revision from cache/database and return the value
+ $rev = self::getCachedRevisionObject( $parser, $t );
+ return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'YmdHis' ) : '';
+ }
+
+ /**
+ * Get the user from the last revision of a specified page.
+ * @param Parser $parser
+ * @param string $title Title to get the user from
+ * @return string
+ * @since 1.23
+ */
+ public static function revisionuser( $parser, $title = null ) {
+ $t = Title::newFromText( $title );
+ if ( is_null( $t ) ) {
+ return '';
+ }
+ // fetch revision from cache/database and return the value
+ $rev = self::getCachedRevisionObject( $parser, $t );
+ return $rev ? $rev->getUserText() : '';
+ }
+
+ /**
+ * Returns the sources of any cascading protection acting on a specified page.
+ * Pages will not return their own title unless they transclude themselves.
+ * This is an expensive parser function and can't be called too many times per page,
+ * unless cascading protection sources for the page have already been loaded.
+ *
+ * @param Parser $parser
+ * @param string $title
+ *
+ * @return string
+ * @since 1.23
+ */
+ public static function cascadingsources( $parser, $title = '' ) {
+ $titleObject = Title::newFromText( $title );
+ if ( !( $titleObject instanceof Title ) ) {
+ $titleObject = $parser->mTitle;
+ }
+ if ( $titleObject->areCascadeProtectionSourcesLoaded()
+ || $parser->incrementExpensiveFunctionCount()
+ ) {
+ $names = array();
+ $sources = $titleObject->getCascadeProtectionSources();
+ foreach ( $sources[0] as $sourceTitle ) {
+ $names[] = $sourceTitle->getPrefixedText();
+ }
+ return implode( $names, '|' );
+ }
+ return '';
+ }
+
}
diff --git a/includes/parser/CoreTagHooks.php b/includes/parser/CoreTagHooks.php
index a2eb6987..85920cc1 100644
--- a/includes/parser/CoreTagHooks.php
+++ b/includes/parser/CoreTagHooks.php
@@ -27,10 +27,10 @@
*/
class CoreTagHooks {
/**
- * @param $parser Parser
+ * @param Parser $parser
* @return void
*/
- static function register( $parser ) {
+ public static function register( $parser ) {
global $wgRawHtml;
$parser->setHook( 'pre', array( __CLASS__, 'pre' ) );
$parser->setHook( 'nowiki', array( __CLASS__, 'nowiki' ) );
@@ -50,7 +50,7 @@ class CoreTagHooks {
* @param Parser $parser
* @return string HTML
*/
- static function pre( $text, $attribs, $parser ) {
+ public static function pre( $text, $attribs, $parser ) {
// Backwards-compatibility hack
$content = StringUtils::delimiterReplace( '<nowiki>', '</nowiki>', '$1', $text, 'i' );
@@ -69,13 +69,13 @@ class CoreTagHooks {
*
* Uses undocumented extended tag hook return values, introduced in r61913.
*
- * @param $content string
- * @param $attributes array
- * @param $parser Parser
+ * @param string $content
+ * @param array $attributes
+ * @param Parser $parser
* @throws MWException
* @return array
*/
- static function html( $content, $attributes, $parser ) {
+ public static function html( $content, $attributes, $parser ) {
global $wgRawHtml;
if ( $wgRawHtml ) {
return array( $content, 'markerType' => 'nowiki' );
@@ -91,12 +91,12 @@ class CoreTagHooks {
*
* Uses undocumented extended tag hook return values, introduced in r61913.
*
- * @param $content string
- * @param $attributes array
- * @param $parser Parser
+ * @param string $content
+ * @param array $attributes
+ * @param Parser $parser
* @return array
*/
- static function nowiki( $content, $attributes, $parser ) {
+ public static function nowiki( $content, $attributes, $parser ) {
$content = strtr( $content, array( '-{' => '-&#123;', '}-' => '&#125;-' ) );
return array( Xml::escapeTagsOnly( $content ), 'markerType' => 'nowiki' );
}
@@ -107,7 +107,7 @@ class CoreTagHooks {
* Renders a thumbnail list of the given images, with optional captions.
* Full syntax documented on the wiki:
*
- * http://www.mediawiki.org/wiki/Help:Images#Gallery_syntax
+ * https://www.mediawiki.org/wiki/Help:Images#Gallery_syntax
*
* @todo break Parser::renderImageGallery out here too.
*
@@ -116,7 +116,7 @@ class CoreTagHooks {
* @param Parser $parser
* @return string HTML
*/
- static function gallery( $content, $attributes, $parser ) {
+ public static function gallery( $content, $attributes, $parser ) {
return $parser->renderImageGallery( $content, $attributes );
}
}
diff --git a/includes/parser/DateFormatter.php b/includes/parser/DateFormatter.php
index 0a69b045..82f0e9d4 100644
--- a/includes/parser/DateFormatter.php
+++ b/includes/parser/DateFormatter.php
@@ -27,11 +27,11 @@
* @ingroup Parser
*/
class DateFormatter {
- var $mSource, $mTarget;
- var $monthNames = '', $rxDM, $rxMD, $rxDMY, $rxYDM, $rxMDY, $rxYMD;
+ public $mSource, $mTarget;
+ public $monthNames = '', $rxDM, $rxMD, $rxDMY, $rxYDM, $rxMDY, $rxYMD;
- var $regexes, $pDays, $pMonths, $pYears;
- var $rules, $xMonths, $preferences;
+ public $regexes, $pDays, $pMonths, $pYears;
+ public $rules, $xMonths, $preferences;
protected $lang;
@@ -49,9 +49,9 @@ class DateFormatter {
const LAST = 8;
/**
- * @param $lang Language In which language to format the date
+ * @param Language $lang In which language to format the date
*/
- function __construct( Language $lang ) {
+ public function __construct( Language $lang ) {
$this->lang = $lang;
$this->monthNames = $this->getMonthRegex();
@@ -120,9 +120,9 @@ class DateFormatter {
/**
* Get a DateFormatter object
*
- * @param $lang Language|string|null In which language to format the date
+ * @param Language|string|null $lang In which language to format the date
* Defaults to the site content language
- * @return DateFormatter object
+ * @return DateFormatter
*/
public static function &getInstance( $lang = null ) {
global $wgMemc, $wgContLang;
@@ -142,10 +142,11 @@ class DateFormatter {
/**
* @param string $preference User preference
* @param string $text Text to reformat
- * @param array $options can contain 'linked' and/or 'match-whole'
- * @return mixed|String
+ * @param array $options Array can contain 'linked' and/or 'match-whole'
+ *
+ * @return string
*/
- function reformat( $preference, $text, $options = array( 'linked' ) ) {
+ public function reformat( $preference, $text, $options = array( 'linked' ) ) {
$linked = in_array( 'linked', $options );
$match_whole = in_array( 'match-whole', $options );
@@ -192,10 +193,10 @@ class DateFormatter {
}
/**
- * @param $matches
+ * @param array $matches
* @return string
*/
- function replace( $matches ) {
+ public function replace( $matches ) {
# Extract information from $matches
$linked = true;
if ( isset( $this->mLinked ) ) {
@@ -204,7 +205,8 @@ class DateFormatter {
$bits = array();
$key = $this->keys[$this->mSource];
- for ( $p = 0; $p < strlen( $key ); $p++ ) {
+ $keyLength = strlen( $key );
+ for ( $p = 0; $p < $keyLength; $p++ ) {
if ( $key[$p] != ' ' ) {
$bits[$key[$p]] = $matches[$p + 1];
}
@@ -214,11 +216,11 @@ class DateFormatter {
}
/**
- * @param $bits array
- * @param $link bool
+ * @param array $bits
+ * @param bool $link
* @return string
*/
- function formatDate( $bits, $link = true ) {
+ public function formatDate( $bits, $link = true ) {
$format = $this->targets[$this->mTarget];
if ( !$link ) {
@@ -253,7 +255,8 @@ class DateFormatter {
$bits['d'] = sprintf( '%02d', $bits['j'] );
}
- for ( $p = 0; $p < strlen( $format ); $p++ ) {
+ $formatLength = strlen( $format );
+ for ( $p = 0; $p < $formatLength; $p++ ) {
$char = $format[$p];
switch ( $char ) {
case 'd': # ISO day of month
@@ -292,6 +295,7 @@ class DateFormatter {
}
}
if ( $fail ) {
+ /** @todo FIXME: $matches doesn't exist here, what's expected? */
$text = $matches[0];
}
@@ -314,7 +318,7 @@ class DateFormatter {
* @todo document
* @return string
*/
- function getMonthRegex() {
+ public function getMonthRegex() {
$names = array();
for ( $i = 1; $i <= 12; $i++ ) {
$names[] = $this->lang->getMonthName( $i );
@@ -325,10 +329,10 @@ class DateFormatter {
/**
* Makes an ISO month, e.g. 02, from a month name
- * @param string $monthName month name
+ * @param string $monthName Month name
* @return string ISO month name
*/
- function makeIsoMonth( $monthName ) {
+ public function makeIsoMonth( $monthName ) {
$n = $this->xMonths[$this->lang->lc( $monthName )];
return sprintf( '%02d', $n );
}
@@ -338,7 +342,7 @@ class DateFormatter {
* @param string $year Year name
* @return string ISO year name
*/
- function makeIsoYear( $year ) {
+ public function makeIsoYear( $year ) {
# Assumes the year is in a nice format, as enforced by the regex
if ( substr( $year, -2 ) == 'BC' ) {
$num = intval( substr( $year, 0, -3 ) ) - 1;
@@ -353,9 +357,10 @@ class DateFormatter {
/**
* @todo document
+ * @param string $iso
* @return int|string
*/
- function makeNormalYear( $iso ) {
+ public function makeNormalYear( $iso ) {
if ( $iso[0] == '-' ) {
$text = ( intval( substr( $iso, 1 ) ) + 1 ) . ' BC';
} else {
diff --git a/includes/parser/LinkHolderArray.php b/includes/parser/LinkHolderArray.php
index f1a0b258..7794fae4 100644
--- a/includes/parser/LinkHolderArray.php
+++ b/includes/parser/LinkHolderArray.php
@@ -25,19 +25,27 @@
* @ingroup Parser
*/
class LinkHolderArray {
- var $internals = array(), $interwikis = array();
- var $size = 0;
- var $parent;
+ public $internals = array();
+ public $interwikis = array();
+ public $size = 0;
+
+ /**
+ * @var Parser
+ */
+ public $parent;
protected $tempIdOffset;
- function __construct( $parent ) {
+ /**
+ * @param Parser $parent
+ */
+ public function __construct( $parent ) {
$this->parent = $parent;
}
/**
* Reduce memory usage to reduce the impact of circular references
*/
- function __destruct() {
+ public function __destruct() {
foreach ( $this as $name => $value ) {
unset( $this->$name );
}
@@ -49,9 +57,9 @@ class LinkHolderArray {
* serializing at present.
*
* Compact the titles, only serialize the text form.
- * @return array
- */
- function __sleep() {
+ * @return array
+ */
+ public function __sleep() {
foreach ( $this->internals as &$nsLinks ) {
foreach ( $nsLinks as &$entry ) {
unset( $entry['title'] );
@@ -71,7 +79,7 @@ class LinkHolderArray {
/**
* Recreate the Title objects
*/
- function __wakeup() {
+ public function __wakeup() {
foreach ( $this->internals as &$nsLinks ) {
foreach ( $nsLinks as &$entry ) {
$entry['title'] = Title::newFromText( $entry['pdbk'] );
@@ -88,9 +96,9 @@ class LinkHolderArray {
/**
* Merge another LinkHolderArray into this one
- * @param $other LinkHolderArray
+ * @param LinkHolderArray $other
*/
- function merge( $other ) {
+ public function merge( $other ) {
foreach ( $other->internals as $ns => $entries ) {
$this->size += count( $entries );
if ( !isset( $this->internals[$ns] ) ) {
@@ -110,11 +118,11 @@ class LinkHolderArray {
* converted for use in the destination link holder. The resulting array of
* strings will be returned.
*
- * @param $other LinkHolderArray
- * @param array $texts of strings
- * @return Array
+ * @param LinkHolderArray $other
+ * @param array $texts Array of strings
+ * @return array
*/
- function mergeForeign( $other, $texts ) {
+ public function mergeForeign( $other, $texts ) {
$this->tempIdOffset = $idOffset = $this->parent->nextLinkID();
$maxId = 0;
@@ -144,6 +152,10 @@ class LinkHolderArray {
return $texts;
}
+ /**
+ * @param array $m
+ * @return string
+ */
protected function mergeForeignCallback( $m ) {
return $m[1] . ( $m[2] + $this->tempIdOffset ) . $m[3];
}
@@ -151,17 +163,18 @@ class LinkHolderArray {
/**
* Get a subset of the current LinkHolderArray which is sufficient to
* interpret the given text.
+ * @param string $text
* @return LinkHolderArray
*/
- function getSubArray( $text ) {
+ public function getSubArray( $text ) {
$sub = new LinkHolderArray( $this->parent );
# Internal links
$pos = 0;
while ( $pos < strlen( $text ) ) {
if ( !preg_match( '/<!--LINK (\d+):(\d+)-->/',
- $text, $m, PREG_OFFSET_CAPTURE, $pos ) )
- {
+ $text, $m, PREG_OFFSET_CAPTURE, $pos )
+ ) {
break;
}
$ns = $m[1][0];
@@ -187,7 +200,7 @@ class LinkHolderArray {
* Returns true if the memory requirements of this object are getting large
* @return bool
*/
- function isBig() {
+ public function isBig() {
global $wgLinkHolderBatchSize;
return $this->size > $wgLinkHolderBatchSize;
}
@@ -196,7 +209,7 @@ class LinkHolderArray {
* Clear all stored link holders.
* Make sure you don't have any text left using these link holders, before you call this
*/
- function clear() {
+ public function clear() {
$this->internals = array();
$this->interwikis = array();
$this->size = 0;
@@ -208,14 +221,14 @@ class LinkHolderArray {
* parsing of interwiki links, and secondly to allow all existence checks and
* article length checks (for stub links) to be bundled into a single query.
*
- * @param $nt Title
- * @param $text String
+ * @param Title $nt
+ * @param string $text
* @param array $query [optional]
* @param string $trail [optional]
* @param string $prefix [optional]
* @return string
*/
- function makeHolder( $nt, $text = '', $query = array(), $trail = '', $prefix = '' ) {
+ public function makeHolder( $nt, $text = '', $query = array(), $trail = '', $prefix = '' ) {
wfProfileIn( __METHOD__ );
if ( !is_object( $nt ) ) {
# Fail gracefully
@@ -251,15 +264,16 @@ class LinkHolderArray {
}
/**
- * @todo FIXME: Update documentation. makeLinkObj() is deprecated.
* Replace <!--LINK--> link placeholders with actual links, in the buffer
- * Placeholders created in Skin::makeLinkObj()
- * @return array of link CSS classes, indexed by PDBK.
+ *
+ * @param string $text
+ * @return array Array of link CSS classes, indexed by PDBK.
*/
- function replace( &$text ) {
+ public function replace( &$text ) {
wfProfileIn( __METHOD__ );
- $colours = $this->replaceInternal( $text ); // FIXME: replaceInternal doesn't return a value
+ /** @todo FIXME: replaceInternal doesn't return a value */
+ $colours = $this->replaceInternal( $text );
$this->replaceInterwiki( $text );
wfProfileOut( __METHOD__ );
@@ -268,6 +282,7 @@ class LinkHolderArray {
/**
* Replace internal links
+ * @param string $text
*/
protected function replaceInternal( &$text ) {
if ( !$this->internals ) {
@@ -275,93 +290,99 @@ class LinkHolderArray {
}
wfProfileIn( __METHOD__ );
- global $wgContLang;
+ global $wgContLang, $wgContentHandlerUseDB;
$colours = array();
$linkCache = LinkCache::singleton();
$output = $this->parent->getOutput();
- if ( $linkCache->useDatabase() ) {
- wfProfileIn( __METHOD__ . '-check' );
- $dbr = wfGetDB( DB_SLAVE );
- $threshold = $this->parent->getOptions()->getStubThreshold();
+ wfProfileIn( __METHOD__ . '-check' );
+ $dbr = wfGetDB( DB_SLAVE );
+ $threshold = $this->parent->getOptions()->getStubThreshold();
- # Sort by namespace
- ksort( $this->internals );
+ # Sort by namespace
+ ksort( $this->internals );
- $linkcolour_ids = array();
+ $linkcolour_ids = array();
- # Generate query
- $queries = array();
- foreach ( $this->internals as $ns => $entries ) {
- foreach ( $entries as $entry ) {
- $title = $entry['title'];
- $pdbk = $entry['pdbk'];
+ # Generate query
+ $queries = array();
+ foreach ( $this->internals as $ns => $entries ) {
+ foreach ( $entries as $entry ) {
+ /** @var Title $title */
+ $title = $entry['title'];
+ $pdbk = $entry['pdbk'];
- # Skip invalid entries.
- # Result will be ugly, but prevents crash.
- if ( is_null( $title ) ) {
- continue;
- }
+ # Skip invalid entries.
+ # Result will be ugly, but prevents crash.
+ if ( is_null( $title ) ) {
+ continue;
+ }
- # Check if it's a static known link, e.g. interwiki
- if ( $title->isAlwaysKnown() ) {
- $colours[$pdbk] = '';
- } elseif ( $ns == NS_SPECIAL ) {
- $colours[$pdbk] = 'new';
- } elseif ( ( $id = $linkCache->getGoodLinkID( $pdbk ) ) != 0 ) {
- $colours[$pdbk] = Linker::getLinkColour( $title, $threshold );
- $output->addLink( $title, $id );
- $linkcolour_ids[$id] = $pdbk;
- } elseif ( $linkCache->isBadLink( $pdbk ) ) {
- $colours[$pdbk] = 'new';
- } else {
- # Not in the link cache, add it to the query
- $queries[$ns][] = $title->getDBkey();
- }
+ # Check if it's a static known link, e.g. interwiki
+ if ( $title->isAlwaysKnown() ) {
+ $colours[$pdbk] = '';
+ } elseif ( $ns == NS_SPECIAL ) {
+ $colours[$pdbk] = 'new';
+ } elseif ( ( $id = $linkCache->getGoodLinkID( $pdbk ) ) != 0 ) {
+ $colours[$pdbk] = Linker::getLinkColour( $title, $threshold );
+ $output->addLink( $title, $id );
+ $linkcolour_ids[$id] = $pdbk;
+ } elseif ( $linkCache->isBadLink( $pdbk ) ) {
+ $colours[$pdbk] = 'new';
+ } else {
+ # Not in the link cache, add it to the query
+ $queries[$ns][] = $title->getDBkey();
}
}
- if ( $queries ) {
- $where = array();
- foreach ( $queries as $ns => $pages ) {
- $where[] = $dbr->makeList(
- array(
- 'page_namespace' => $ns,
- 'page_title' => $pages,
- ),
- LIST_AND
- );
- }
-
- $res = $dbr->select(
- 'page',
- array( 'page_id', 'page_namespace', 'page_title', 'page_is_redirect', 'page_len', 'page_latest' ),
- $dbr->makeList( $where, LIST_OR ),
- __METHOD__
+ }
+ if ( $queries ) {
+ $where = array();
+ foreach ( $queries as $ns => $pages ) {
+ $where[] = $dbr->makeList(
+ array(
+ 'page_namespace' => $ns,
+ 'page_title' => array_unique( $pages ),
+ ),
+ LIST_AND
);
+ }
- # Fetch data and form into an associative array
- # non-existent = broken
- foreach ( $res as $s ) {
- $title = Title::makeTitle( $s->page_namespace, $s->page_title );
- $pdbk = $title->getPrefixedDBkey();
- $linkCache->addGoodLinkObjFromRow( $title, $s );
- $output->addLink( $title, $s->page_id );
- # @todo FIXME: Convoluted data flow
- # The redirect status and length is passed to getLinkColour via the LinkCache
- # Use formal parameters instead
- $colours[$pdbk] = Linker::getLinkColour( $title, $threshold );
- //add id to the extension todolist
- $linkcolour_ids[$s->page_id] = $pdbk;
- }
- unset( $res );
+ $fields = array( 'page_id', 'page_namespace', 'page_title',
+ 'page_is_redirect', 'page_len', 'page_latest' );
+
+ if ( $wgContentHandlerUseDB ) {
+ $fields[] = 'page_content_model';
}
- if ( count( $linkcolour_ids ) ) {
- //pass an array of page_ids to an extension
- wfRunHooks( 'GetLinkColours', array( $linkcolour_ids, &$colours ) );
+
+ $res = $dbr->select(
+ 'page',
+ $fields,
+ $dbr->makeList( $where, LIST_OR ),
+ __METHOD__
+ );
+
+ # Fetch data and form into an associative array
+ # non-existent = broken
+ foreach ( $res as $s ) {
+ $title = Title::makeTitle( $s->page_namespace, $s->page_title );
+ $pdbk = $title->getPrefixedDBkey();
+ $linkCache->addGoodLinkObjFromRow( $title, $s );
+ $output->addLink( $title, $s->page_id );
+ # @todo FIXME: Convoluted data flow
+ # The redirect status and length is passed to getLinkColour via the LinkCache
+ # Use formal parameters instead
+ $colours[$pdbk] = Linker::getLinkColour( $title, $threshold );
+ //add id to the extension todolist
+ $linkcolour_ids[$s->page_id] = $pdbk;
}
- wfProfileOut( __METHOD__ . '-check' );
+ unset( $res );
}
+ if ( count( $linkcolour_ids ) ) {
+ //pass an array of page_ids to an extension
+ wfRunHooks( 'GetLinkColours', array( $linkcolour_ids, &$colours ) );
+ }
+ wfProfileOut( __METHOD__ . '-check' );
# Do a second query for different language variants of links and categories
if ( $wgContLang->hasVariants() ) {
@@ -421,6 +442,7 @@ class LinkHolderArray {
/**
* Replace interwiki links
+ * @param string $text
*/
protected function replaceInterwiki( &$text ) {
if ( empty( $this->interwikis ) ) {
@@ -446,9 +468,10 @@ class LinkHolderArray {
/**
* Modify $this->internals and $colours according to language variant linking rules
+ * @param array $colours
*/
protected function doVariants( &$colours ) {
- global $wgContLang;
+ global $wgContLang, $wgContentHandlerUseDB;
$linkBatch = new LinkBatch();
$variantMap = array(); // maps $pdbkey_Variant => $keys (of link holders)
$output = $this->parent->getOutput();
@@ -486,6 +509,7 @@ class LinkHolderArray {
// Then add variants of links to link batch
$parentTitle = $this->parent->getTitle();
foreach ( $titlesAttrs as $i => $attrs ) {
+ /** @var Title $title */
list( $index, $title ) = $attrs;
$ns = $title->getNamespace();
$text = $title->getText();
@@ -504,7 +528,7 @@ class LinkHolderArray {
// Self-link checking for mixed/different variant titles. At this point, we
// already know the exact title does not exist, so the link cannot be to a
// variant of the current title that exists as a separate page.
- if ( $variantTitle->equals( $parentTitle ) && $title->getFragment() === '' ) {
+ if ( $variantTitle->equals( $parentTitle ) && !$title->hasFragment() ) {
$this->internals[$ns][$index]['selflink'] = true;
continue 2;
}
@@ -536,8 +560,15 @@ class LinkHolderArray {
if ( !$linkBatch->isEmpty() ) {
// construct query
$dbr = wfGetDB( DB_SLAVE );
+ $fields = array( 'page_id', 'page_namespace', 'page_title',
+ 'page_is_redirect', 'page_len', 'page_latest' );
+
+ if ( $wgContentHandlerUseDB ) {
+ $fields[] = 'page_content_model';
+ }
+
$varRes = $dbr->select( 'page',
- array( 'page_id', 'page_namespace', 'page_title', 'page_is_redirect', 'page_len', 'page_latest' ),
+ $fields,
$linkBatch->constructSet( 'page', $dbr ),
__METHOD__
);
@@ -609,10 +640,10 @@ class LinkHolderArray {
* Replace <!--LINK--> link placeholders with plain text of links
* (not HTML-formatted).
*
- * @param $text String
- * @return String
+ * @param string $text
+ * @return string
*/
- function replaceText( $text ) {
+ public function replaceText( $text ) {
wfProfileIn( __METHOD__ );
$text = preg_replace_callback(
@@ -627,11 +658,11 @@ class LinkHolderArray {
/**
* Callback for replaceText()
*
- * @param $matches Array
+ * @param array $matches
* @return string
* @private
*/
- function replaceTextCallback( $matches ) {
+ public function replaceTextCallback( $matches ) {
$type = $matches[1];
$key = $matches[2];
if ( $type == 'LINK' ) {
diff --git a/includes/parser/Tidy.php b/includes/parser/MWTidy.php
index 32b16aaf..b310862f 100644
--- a/includes/parser/Tidy.php
+++ b/includes/parser/MWTidy.php
@@ -50,7 +50,7 @@ class MWTidyWrapper {
}
/**
- * @param $text string
+ * @param string $text
* @return string
*/
public function getWrapped( $text ) {
@@ -65,7 +65,9 @@ class MWTidyWrapper {
// ...and <mw:toc> markers
$wrappedtext = preg_replace_callback( '/\<\\/?mw:toc\>/',
array( &$this, 'replaceCallback' ), $wrappedtext );
-
+ // ... and <math> tags
+ $wrappedtext = preg_replace_callback( '/\<math(.*?)\<\\/math\>/s',
+ array( &$this, 'replaceCallback' ), $wrappedtext );
// Modify inline Microdata <link> and <meta> elements so they say <html-link> and <html-meta> so
// we can trick Tidy into not stripping them out by including them in tidy's new-empty-tags config
$wrappedtext = preg_replace( '!<(link|meta)([^>]*?)(/{0,1}>)!', '<html-$1$2$3', $wrappedtext );
@@ -79,11 +81,11 @@ class MWTidyWrapper {
}
/**
- * @param $m array
+ * @param array $m
*
* @return string
*/
- function replaceCallback( $m ) {
+ public function replaceCallback( $m ) {
$marker = "{$this->mUniqPrefix}-item-{$this->mMarkerIndex}" . Parser::MARKER_SUFFIX;
$this->mMarkerIndex++;
$this->mTokens->setPair( $marker, $m[0] );
@@ -91,7 +93,7 @@ class MWTidyWrapper {
}
/**
- * @param $text string
+ * @param string $text
* @return string
*/
public function postprocess( $text ) {
@@ -121,8 +123,8 @@ class MWTidy {
* If tidy isn't able to correct the markup, the original will be
* returned in all its glory with a warning comment appended.
*
- * @param string $text hideous HTML input
- * @return String: corrected HTML output
+ * @param string $text Hideous HTML input
+ * @return string Corrected HTML output
*/
public static function tidy( $text ) {
global $wgTidyInternal;
@@ -153,9 +155,9 @@ class MWTidy {
/**
* Check HTML for errors, used if $wgValidateAllHtml = true.
*
- * @param $text String
- * @param &$errorStr String: return the error string
- * @return Boolean: whether the HTML is valid
+ * @param string $text
+ * @param string &$errorStr Return the error string
+ * @return bool Whether the HTML is valid
*/
public static function checkErrors( $text, &$errorStr = null ) {
global $wgTidyInternal;
@@ -175,9 +177,9 @@ class MWTidy {
* Also called in OutputHandler.php for full page validation
*
* @param string $text HTML to check
- * @param $stderr Boolean: Whether to read result from STDERR rather than STDOUT
- * @param &$retval int Exit code (-1 on internal error)
- * @return mixed String or null
+ * @param bool $stderr Whether to read result from STDERR rather than STDOUT
+ * @param int &$retval Exit code (-1 on internal error)
+ * @return string|null
*/
private static function execExternalTidy( $text, $stderr = false, &$retval = null ) {
global $wgTidyConf, $wgTidyBin, $wgTidyOpts;
@@ -206,6 +208,9 @@ class MWTidy {
$process = proc_open(
"$wgTidyBin -config $wgTidyConf $wgTidyOpts$opts", $descriptorspec, $pipes );
+ //NOTE: At least on linux, the process will be created even if tidy is not installed.
+ // This means that missing tidy will be treated as a validation failure.
+
if ( is_resource( $process ) ) {
// Theoretically, this style of communication could cause a deadlock
// here. If the stdout buffer fills up, then writes to stdin could
@@ -239,9 +244,9 @@ class MWTidy {
* saving the overhead of spawning a new process.
*
* @param string $text HTML to check
- * @param $stderr Boolean: Whether to read result from error status instead of output
- * @param &$retval int Exit code (-1 on internal error)
- * @return mixed String or null
+ * @param bool $stderr Whether to read result from error status instead of output
+ * @param int &$retval Exit code (-1 on internal error)
+ * @return string|null
*/
private static function execInternalTidy( $text, $stderr = false, &$retval = null ) {
global $wgTidyConf, $wgDebugTidy;
diff --git a/includes/parser/Parser.php b/includes/parser/Parser.php
index 1f14223d..84bb2243 100644
--- a/includes/parser/Parser.php
+++ b/includes/parser/Parser.php
@@ -120,62 +120,61 @@ class Parser {
const TOC_END = '</mw:toc>';
# Persistent:
- var $mTagHooks = array();
- var $mTransparentTagHooks = array();
- var $mFunctionHooks = array();
- var $mFunctionSynonyms = array( 0 => array(), 1 => array() );
- var $mFunctionTagHooks = array();
- var $mStripList = array();
- var $mDefaultStripList = array();
- var $mVarCache = array();
- var $mImageParams = array();
- var $mImageParamsMagicArray = array();
- var $mMarkerIndex = 0;
- var $mFirstCall = true;
+ public $mTagHooks = array();
+ public $mTransparentTagHooks = array();
+ public $mFunctionHooks = array();
+ public $mFunctionSynonyms = array( 0 => array(), 1 => array() );
+ public $mFunctionTagHooks = array();
+ public $mStripList = array();
+ public $mDefaultStripList = array();
+ public $mVarCache = array();
+ public $mImageParams = array();
+ public $mImageParamsMagicArray = array();
+ public $mMarkerIndex = 0;
+ public $mFirstCall = true;
# Initialised by initialiseVariables()
/**
* @var MagicWordArray
*/
- var $mVariables;
+ public $mVariables;
/**
* @var MagicWordArray
*/
- var $mSubstWords;
- var $mConf, $mPreprocessor, $mExtLinkBracketedRegex, $mUrlProtocols; # Initialised in constructor
+ public $mSubstWords;
+ public $mConf, $mPreprocessor, $mExtLinkBracketedRegex, $mUrlProtocols; # Initialised in constructor
# Cleared with clearState():
/**
* @var ParserOutput
*/
- var $mOutput;
- var $mAutonumber, $mDTopen;
+ public $mOutput;
+ public $mAutonumber, $mDTopen;
/**
* @var StripState
*/
- var $mStripState;
+ public $mStripState;
- var $mIncludeCount, $mArgStack, $mLastSection, $mInPre;
+ public $mIncludeCount, $mArgStack, $mLastSection, $mInPre;
/**
* @var LinkHolderArray
*/
- var $mLinkHolders;
+ public $mLinkHolders;
- var $mLinkID;
- var $mIncludeSizes, $mPPNodeCount, $mGeneratedPPNodeCount, $mHighestExpansionDepth;
- var $mDefaultSort;
- var $mTplExpandCache; # empty-frame expansion cache
- var $mTplRedirCache, $mTplDomCache, $mHeadings, $mDoubleUnderscores;
- var $mExpensiveFunctionCount; # number of expensive parser function calls
- var $mShowToc, $mForceTocPosition;
+ public $mLinkID;
+ public $mIncludeSizes, $mPPNodeCount, $mGeneratedPPNodeCount, $mHighestExpansionDepth;
+ public $mDefaultSort;
+ public $mTplRedirCache, $mTplDomCache, $mHeadings, $mDoubleUnderscores;
+ public $mExpensiveFunctionCount; # number of expensive parser function calls
+ public $mShowToc, $mForceTocPosition;
/**
* @var User
*/
- var $mUser; # User object; only used when doing pre-save transform
+ public $mUser; # User object; only used when doing pre-save transform
# Temporary
# These are variables reset at least once per parse regardless of $clearState
@@ -183,38 +182,42 @@ class Parser {
/**
* @var ParserOptions
*/
- var $mOptions;
+ public $mOptions;
/**
* @var Title
*/
- var $mTitle; # Title context, used for self-link rendering and similar things
- var $mOutputType; # Output type, one of the OT_xxx constants
- var $ot; # Shortcut alias, see setOutputType()
- var $mRevisionObject; # The revision object of the specified revision ID
- var $mRevisionId; # ID to display in {{REVISIONID}} tags
- var $mRevisionTimestamp; # The timestamp of the specified revision ID
- var $mRevisionUser; # User to display in {{REVISIONUSER}} tag
- var $mRevisionSize; # Size to display in {{REVISIONSIZE}} variable
- var $mRevIdForTs; # The revision ID which was used to fetch the timestamp
- var $mInputSize = false; # For {{PAGESIZE}} on current page.
+ public $mTitle; # Title context, used for self-link rendering and similar things
+ public $mOutputType; # Output type, one of the OT_xxx constants
+ public $ot; # Shortcut alias, see setOutputType()
+ public $mRevisionObject; # The revision object of the specified revision ID
+ public $mRevisionId; # ID to display in {{REVISIONID}} tags
+ public $mRevisionTimestamp; # The timestamp of the specified revision ID
+ public $mRevisionUser; # User to display in {{REVISIONUSER}} tag
+ public $mRevisionSize; # Size to display in {{REVISIONSIZE}} variable
+ public $mRevIdForTs; # The revision ID which was used to fetch the timestamp
+ public $mInputSize = false; # For {{PAGESIZE}} on current page.
/**
* @var string
*/
- var $mUniqPrefix;
+ public $mUniqPrefix;
/**
- * @var Array with the language name of each language link (i.e. the
+ * @var array Array with the language name of each language link (i.e. the
* interwiki prefix) in the key, value arbitrary. Used to avoid sending
* duplicate language links to the ParserOutput.
*/
- var $mLangLinkLanguages;
+ public $mLangLinkLanguages;
/**
- * Constructor
- *
- * @param $conf array
+ * @var bool Recursive call protection.
+ * This variable should be treated as if it were private.
+ */
+ public $mInParse = false;
+
+ /**
+ * @param array $conf
*/
public function __construct( $conf = array() ) {
$this->mConf = $conf;
@@ -241,7 +244,7 @@ class Parser {
/**
* Reduce memory usage to reduce the impact of circular references
*/
- function __destruct() {
+ public function __destruct() {
if ( isset( $this->mLinkHolders ) ) {
unset( $this->mLinkHolders );
}
@@ -253,14 +256,15 @@ class Parser {
/**
* Allow extensions to clean up when the parser is cloned
*/
- function __clone() {
+ public function __clone() {
+ $this->mInParse = false;
wfRunHooks( 'ParserCloned', array( $this ) );
}
/**
* Do various kinds of initialisation on the first call of the parser
*/
- function firstCallInit() {
+ public function firstCallInit() {
if ( !$this->mFirstCall ) {
return;
}
@@ -281,7 +285,7 @@ class Parser {
*
* @private
*/
- function clearState() {
+ public function clearState() {
wfProfileIn( __METHOD__ );
if ( $this->mFirstCall ) {
$this->firstCallInit();
@@ -316,7 +320,7 @@ class Parser {
$this->mStripState = new StripState( $this->mUniqPrefix );
# Clear these on every parse, bug 4549
- $this->mTplExpandCache = $this->mTplRedirCache = $this->mTplDomCache = array();
+ $this->mTplRedirCache = $this->mTplDomCache = array();
$this->mShowToc = true;
$this->mForceTocPosition = false;
@@ -345,15 +349,17 @@ class Parser {
* Convert wikitext to HTML
* Do not call this function recursively.
*
- * @param string $text text we want to parse
- * @param $title Title object
- * @param $options ParserOptions
- * @param $linestart boolean
- * @param $clearState boolean
- * @param int $revid number to pass in {{REVISIONID}}
- * @return ParserOutput a ParserOutput
- */
- public function parse( $text, Title $title, ParserOptions $options, $linestart = true, $clearState = true, $revid = null ) {
+ * @param string $text Text we want to parse
+ * @param Title $title
+ * @param ParserOptions $options
+ * @param bool $linestart
+ * @param bool $clearState
+ * @param int $revid Number to pass in {{REVISIONID}}
+ * @return ParserOutput A ParserOutput
+ */
+ public function parse( $text, Title $title, ParserOptions $options,
+ $linestart = true, $clearState = true, $revid = null
+ ) {
/**
* First pass--just handle <nowiki> sections, pass the rest off
* to internalParse() which does all the real work.
@@ -364,6 +370,10 @@ class Parser {
wfProfileIn( __METHOD__ );
wfProfileIn( $fname );
+ if ( $clearState ) {
+ $magicScopeVariable = $this->lock();
+ }
+
$this->startParse( $title, $options, self::OT_HTML, $clearState );
$this->mInputSize = strlen( $text );
@@ -420,8 +430,8 @@ class Parser {
* d) it is an interface message (which is in the user language)
*/
if ( !( $options->getDisableContentConversion()
- || isset( $this->mDoubleUnderscores['nocontentconvert'] ) ) )
- {
+ || isset( $this->mDoubleUnderscores['nocontentconvert'] ) )
+ ) {
if ( !$this->mOptions->getInterfaceMessage() ) {
# The position of the convert() call should not be changed. it
# assumes that the links are all replaced and the only thing left
@@ -438,10 +448,10 @@ class Parser {
* automatic link conversion.
*/
if ( !( $options->getDisableTitleConversion()
- || isset( $this->mDoubleUnderscores['nocontentconvert'] )
- || isset( $this->mDoubleUnderscores['notitleconvert'] )
- || $this->mOutput->getDisplayTitle() !== false ) )
- {
+ || isset( $this->mDoubleUnderscores['nocontentconvert'] )
+ || isset( $this->mDoubleUnderscores['notitleconvert'] )
+ || $this->mOutput->getDisplayTitle() !== false )
+ ) {
$convruletitle = $this->getConverterLanguage()->getConvRuleTitle();
if ( $convruletitle ) {
$this->mOutput->setTitleText( $convruletitle );
@@ -541,7 +551,7 @@ class Parser {
}
foreach ( $this->mOutput->getLimitReportData() as $key => $value ) {
if ( wfRunHooks( 'ParserLimitReportFormat',
- array( $key, $value, &$limitReport, false, false )
+ array( $key, &$value, &$limitReport, false, false )
) ) {
$keyMsg = wfMessage( $key )->inLanguage( 'en' )->useDatabase( false );
$valueMsg = wfMessage( array( "$key-value-text", "$key-value" ) )
@@ -590,12 +600,12 @@ class Parser {
*
* If $frame is not provided, then template variables (e.g., {{{1}}}) within $text are not expanded
*
- * @param string $text text extension wants to have parsed
- * @param $frame PPFrame: The frame to use for expanding any template variables
+ * @param string $text Text extension wants to have parsed
+ * @param bool|PPFrame $frame The frame to use for expanding any template variables
*
* @return string
*/
- function recursiveTagParse( $text, $frame = false ) {
+ public function recursiveTagParse( $text, $frame = false ) {
wfProfileIn( __METHOD__ );
wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
@@ -607,17 +617,24 @@ class Parser {
/**
* Expand templates and variables in the text, producing valid, static wikitext.
* Also removes comments.
+ * Do not call this function recursively.
+ * @param string $text
+ * @param Title $title
+ * @param ParserOptions $options
+ * @param int|null $revid
+ * @param bool|PPFrame $frame
* @return mixed|string
*/
- function preprocess( $text, Title $title = null, ParserOptions $options, $revid = null ) {
+ public function preprocess( $text, Title $title = null, ParserOptions $options, $revid = null, $frame = false ) {
wfProfileIn( __METHOD__ );
+ $magicScopeVariable = $this->lock();
$this->startParse( $title, $options, self::OT_PREPROCESS, true );
if ( $revid !== null ) {
$this->mRevisionId = $revid;
}
wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
- $text = $this->replaceVariables( $text );
+ $text = $this->replaceVariables( $text, $frame );
$text = $this->mStripState->unstripBoth( $text );
wfProfileOut( __METHOD__ );
return $text;
@@ -627,9 +644,9 @@ class Parser {
* Recursive parser entry point that can be called from an extension tag
* hook.
*
- * @param string $text text to be expanded
- * @param $frame PPFrame: The frame to use for expanding any template variables
- * @return String
+ * @param string $text Text to be expanded
+ * @param bool|PPFrame $frame The frame to use for expanding any template variables
+ * @return string
* @since 1.19
*/
public function recursivePreprocess( $text, $frame = false ) {
@@ -647,13 +664,18 @@ class Parser {
* transclusion, comments, templates, arguments, tags hooks and parser
* functions are untouched.
*
- * @param $text String
- * @param $title Title
- * @param $options ParserOptions
- * @return String
+ * @param string $text
+ * @param Title $title
+ * @param ParserOptions $options
+ * @param array $params
+ * @return string
*/
- public function getPreloadText( $text, Title $title, ParserOptions $options ) {
+ public function getPreloadText( $text, Title $title, ParserOptions $options, $params = array() ) {
+ $msg = new RawMessage( $text );
+ $text = $msg->params( $params )->plain();
+
# Parser (re)initialisation
+ $magicScopeVariable = $this->lock();
$this->startParse( $title, $options, self::OT_PLAIN, true );
$flags = PPFrame::NO_ARGS | PPFrame::NO_TEMPLATES;
@@ -676,16 +698,16 @@ class Parser {
* Set the current user.
* Should only be used when doing pre-save transform.
*
- * @param $user Mixed: User object or null (to reset)
+ * @param User|null $user User object or null (to reset)
*/
- function setUser( $user ) {
+ public function setUser( $user ) {
$this->mUser = $user;
}
/**
* Accessor for mUniqPrefix.
*
- * @return String
+ * @return string
*/
public function uniqPrefix() {
if ( !isset( $this->mUniqPrefix ) ) {
@@ -703,14 +725,14 @@ class Parser {
/**
* Set the context title
*
- * @param $t Title
+ * @param Title $t
*/
- function setTitle( $t ) {
- if ( !$t || $t instanceof FakeTitle ) {
+ public function setTitle( $t ) {
+ if ( !$t ) {
$t = Title::newFromText( 'NO TITLE' );
}
- if ( strval( $t->getFragment() ) !== '' ) {
+ if ( $t->hasFragment() ) {
# Strip the fragment to avoid various odd effects
$this->mTitle = clone $t;
$this->mTitle->setFragment( '' );
@@ -722,28 +744,28 @@ class Parser {
/**
* Accessor for the Title object
*
- * @return Title object
+ * @return Title
*/
- function getTitle() {
+ public function getTitle() {
return $this->mTitle;
}
/**
* Accessor/mutator for the Title object
*
- * @param $x Title object or null to just get the current one
- * @return Title object
+ * @param Title $x Title object or null to just get the current one
+ * @return Title
*/
- function Title( $x = null ) {
+ public function Title( $x = null ) {
return wfSetVar( $this->mTitle, $x );
}
/**
* Set the output type
*
- * @param $ot Integer: new value
+ * @param int $ot New value
*/
- function setOutputType( $ot ) {
+ public function setOutputType( $ot ) {
$this->mOutputType = $ot;
# Shortcut alias
$this->ot = array(
@@ -758,51 +780,51 @@ class Parser {
* Accessor/mutator for the output type
*
* @param int|null $x New value or null to just get the current one
- * @return Integer
+ * @return int
*/
- function OutputType( $x = null ) {
+ public function OutputType( $x = null ) {
return wfSetVar( $this->mOutputType, $x );
}
/**
* Get the ParserOutput object
*
- * @return ParserOutput object
+ * @return ParserOutput
*/
- function getOutput() {
+ public function getOutput() {
return $this->mOutput;
}
/**
* Get the ParserOptions object
*
- * @return ParserOptions object
+ * @return ParserOptions
*/
- function getOptions() {
+ public function getOptions() {
return $this->mOptions;
}
/**
* Accessor/mutator for the ParserOptions object
*
- * @param $x ParserOptions New value or null to just get the current one
+ * @param ParserOptions $x New value or null to just get the current one
* @return ParserOptions Current ParserOptions object
*/
- function Options( $x = null ) {
+ public function Options( $x = null ) {
return wfSetVar( $this->mOptions, $x );
}
/**
* @return int
*/
- function nextLinkID() {
+ public function nextLinkID() {
return $this->mLinkID++;
}
/**
- * @param $id int
+ * @param int $id
*/
- function setLinkID( $id ) {
+ public function setLinkID( $id ) {
$this->mLinkID = $id;
}
@@ -810,7 +832,7 @@ class Parser {
* Get a language object for use in parser functions such as {{FORMATNUM:}}
* @return Language
*/
- function getFunctionLang() {
+ public function getFunctionLang() {
return $this->getTargetLanguage();
}
@@ -821,7 +843,7 @@ class Parser {
* @since 1.19
*
* @throws MWException
- * @return Language|null
+ * @return Language
*/
public function getTargetLanguage() {
$target = $this->mOptions->getTargetLanguage();
@@ -839,8 +861,9 @@ class Parser {
/**
* Get the language object for language conversion
+ * @return Language|null
*/
- function getConverterLanguage() {
+ public function getConverterLanguage() {
return $this->getTargetLanguage();
}
@@ -848,9 +871,9 @@ class Parser {
* Get a User object either from $this->mUser, if set, or from the
* ParserOptions object otherwise
*
- * @return User object
+ * @return User
*/
- function getUser() {
+ public function getUser() {
if ( !is_null( $this->mUser ) ) {
return $this->mUser;
}
@@ -860,9 +883,9 @@ class Parser {
/**
* Get a preprocessor object
*
- * @return Preprocessor instance
+ * @return Preprocessor
*/
- function getPreprocessor() {
+ public function getPreprocessor() {
if ( !isset( $this->mPreprocessor ) ) {
$class = $this->mPreprocessorClass;
$this->mPreprocessor = new $class( $this );
@@ -884,11 +907,11 @@ class Parser {
* '<element param="x">tag content</element>' ) )
* @endcode
*
- * @param array $elements list of element names. Comments are always extracted.
+ * @param array $elements List of element names. Comments are always extracted.
* @param string $text Source text string.
* @param array $matches Out parameter, Array: extracted tags
- * @param $uniq_prefix string
- * @return String: stripped text
+ * @param string $uniq_prefix
+ * @return string Stripped text
*/
public static function extractTagsAndParams( $elements, $text, &$matches, $uniq_prefix = '' ) {
static $n = 1;
@@ -957,7 +980,7 @@ class Parser {
*
* @return array
*/
- function getStripList() {
+ public function getStripList() {
return $this->mStripList;
}
@@ -966,11 +989,11 @@ class Parser {
* Returns the unique tag which must be inserted into the stripped text
* The tag will be replaced with the original text in unstrip()
*
- * @param $text string
+ * @param string $text
*
* @return string
*/
- function insertStripItem( $text ) {
+ public function insertStripItem( $text ) {
$rnd = "{$this->mUniqPrefix}-item-{$this->mMarkerIndex}-" . self::MARKER_SUFFIX;
$this->mMarkerIndex++;
$this->mStripState->addGeneral( $rnd, $text );
@@ -981,9 +1004,10 @@ class Parser {
* parse the wiki syntax used to render tables
*
* @private
+ * @param string $text
* @return string
*/
- function doTableStuff( $text ) {
+ public function doTableStuff( $text ) {
wfProfileIn( __METHOD__ );
$lines = StringUtils::explode( "\n", $text );
@@ -1068,7 +1092,10 @@ class Parser {
array_push( $tr_history, false );
array_push( $td_history, false );
array_push( $last_tag_history, '' );
- } elseif ( $first_character === '|' || $first_character === '!' || substr( $line, 0, 2 ) === '|+' ) {
+ } elseif ( $first_character === '|'
+ || $first_character === '!'
+ || substr( $line, 0, 2 ) === '|+'
+ ) {
# This might be cell elements, td, th or captions
if ( substr( $line, 0, 2 ) === '|+' ) {
$first_character = '+';
@@ -1179,13 +1206,13 @@ class Parser {
*
* @private
*
- * @param $text string
- * @param $isMain bool
- * @param $frame bool
+ * @param string $text
+ * @param bool $isMain
+ * @param bool $frame
*
* @return string
*/
- function internalParse( $text, $isMain = true, $frame = false ) {
+ public function internalParse( $text, $isMain = true, $frame = false ) {
wfProfileIn( __METHOD__ );
$origText = $text;
@@ -1213,7 +1240,12 @@ class Parser {
}
wfRunHooks( 'InternalParseBeforeSanitize', array( &$this, &$text, &$this->mStripState ) );
- $text = Sanitizer::removeHTMLtags( $text, array( &$this, 'attributeStripCallback' ), false, array_keys( $this->mTransparentTagHooks ) );
+ $text = Sanitizer::removeHTMLtags(
+ $text,
+ array( &$this, 'attributeStripCallback' ),
+ false,
+ array_keys( $this->mTransparentTagHooks )
+ );
wfRunHooks( 'InternalParseBeforeLinks', array( &$this, &$text, &$this->mStripState ) );
# Tables need to come after variable replacement for things to work
@@ -1249,11 +1281,11 @@ class Parser {
* DML
* @private
*
- * @param $text string
+ * @param string $text
*
* @return string
*/
- function doMagicLinks( $text ) {
+ public function doMagicLinks( $text ) {
wfProfileIn( __METHOD__ );
$prots = wfUrlProtocolsWithoutProtRel();
$urlChar = self::EXT_LINK_URL_CLASS;
@@ -1275,10 +1307,10 @@ class Parser {
/**
* @throws MWException
- * @param $m array
+ * @param array $m
* @return HTML|string
*/
- function magicLinkCallback( $m ) {
+ public function magicLinkCallback( $m ) {
if ( isset( $m[1] ) && $m[1] !== '' ) {
# Skip anchor
return $m[0];
@@ -1293,19 +1325,19 @@ class Parser {
if ( substr( $m[0], 0, 3 ) === 'RFC' ) {
$keyword = 'RFC';
$urlmsg = 'rfcurl';
- $CssClass = 'mw-magiclink-rfc';
+ $cssClass = 'mw-magiclink-rfc';
$id = $m[4];
} elseif ( substr( $m[0], 0, 4 ) === 'PMID' ) {
$keyword = 'PMID';
$urlmsg = 'pubmedurl';
- $CssClass = 'mw-magiclink-pmid';
+ $cssClass = 'mw-magiclink-pmid';
$id = $m[4];
} else {
throw new MWException( __METHOD__ . ': unrecognised match type "' .
substr( $m[0], 0, 20 ) . '"' );
}
$url = wfMessage( $urlmsg, $id )->inContentLanguage()->text();
- return Linker::makeExternalLink( $url, "{$keyword} {$id}", true, $CssClass );
+ return Linker::makeExternalLink( $url, "{$keyword} {$id}", true, $cssClass );
} elseif ( isset( $m[5] ) && $m[5] !== '' ) {
# ISBN
$isbn = $m[5];
@@ -1326,12 +1358,12 @@ class Parser {
/**
* Make a free external link, given a user-supplied URL
*
- * @param $url string
+ * @param string $url
*
* @return string HTML
* @private
*/
- function makeFreeExternalLink( $url ) {
+ public function makeFreeExternalLink( $url ) {
wfProfileIn( __METHOD__ );
$trail = '';
@@ -1370,7 +1402,7 @@ class Parser {
$this->getExternalLinkAttribs( $url ) );
# Register it in the output object...
# Replace unnecessary URL escape codes with their equivalent characters
- $pasteurized = self::replaceUnusualEscapes( $url );
+ $pasteurized = self::normalizeLinkUrl( $url );
$this->mOutput->addExternalLink( $pasteurized );
}
wfProfileOut( __METHOD__ );
@@ -1382,11 +1414,11 @@ class Parser {
*
* @private
*
- * @param $text string
+ * @param string $text
*
* @return string
*/
- function doHeadings( $text ) {
+ public function doHeadings( $text ) {
wfProfileIn( __METHOD__ );
for ( $i = 6; $i >= 1; --$i ) {
$h = str_repeat( '=', $i );
@@ -1400,11 +1432,11 @@ class Parser {
* Replace single quotes with HTML markup
* @private
*
- * @param $text string
+ * @param string $text
*
- * @return string the altered text
+ * @return string The altered text
*/
- function doAllQuotes( $text ) {
+ public function doAllQuotes( $text ) {
wfProfileIn( __METHOD__ );
$outtext = '';
$lines = StringUtils::explode( "\n", $text );
@@ -1419,7 +1451,7 @@ class Parser {
/**
* Helper function for doAllQuotes()
*
- * @param $text string
+ * @param string $text
*
* @return string
*/
@@ -1608,18 +1640,19 @@ class Parser {
*
* @private
*
- * @param $text string
+ * @param string $text
*
* @throws MWException
* @return string
*/
- function replaceExternalLinks( $text ) {
+ public function replaceExternalLinks( $text ) {
wfProfileIn( __METHOD__ );
$bits = preg_split( $this->mExtLinkBracketedRegex, $text, -1, PREG_SPLIT_DELIM_CAPTURE );
if ( $bits === false ) {
wfProfileOut( __METHOD__ );
- throw new MWException( "PCRE needs to be compiled with --enable-unicode-properties in order for MediaWiki to function" );
+ throw new MWException( "PCRE needs to be compiled with "
+ . "--enable-unicode-properties in order for MediaWiki to function" );
}
$s = array_shift( $bits );
@@ -1677,43 +1710,45 @@ class Parser {
# Register link in the output object.
# Replace unnecessary URL escape codes with the referenced character
# This prevents spammers from hiding links from the filters
- $pasteurized = self::replaceUnusualEscapes( $url );
+ $pasteurized = self::normalizeLinkUrl( $url );
$this->mOutput->addExternalLink( $pasteurized );
}
wfProfileOut( __METHOD__ );
return $s;
}
+
/**
* Get the rel attribute for a particular external link.
*
* @since 1.21
- * @param string|bool $url optional URL, to extract the domain from for rel =>
+ * @param string|bool $url Optional URL, to extract the domain from for rel =>
* nofollow if appropriate
- * @param $title Title optional Title, for wgNoFollowNsExceptions lookups
- * @return string|null rel attribute for $url
+ * @param Title $title Optional Title, for wgNoFollowNsExceptions lookups
+ * @return string|null Rel attribute for $url
*/
public static function getExternalLinkRel( $url = false, $title = null ) {
global $wgNoFollowLinks, $wgNoFollowNsExceptions, $wgNoFollowDomainExceptions;
$ns = $title ? $title->getNamespace() : false;
- if ( $wgNoFollowLinks && !in_array( $ns, $wgNoFollowNsExceptions ) &&
- !wfMatchesDomainList( $url, $wgNoFollowDomainExceptions ) )
- {
+ if ( $wgNoFollowLinks && !in_array( $ns, $wgNoFollowNsExceptions )
+ && !wfMatchesDomainList( $url, $wgNoFollowDomainExceptions )
+ ) {
return 'nofollow';
}
return null;
}
+
/**
* Get an associative array of additional HTML attributes appropriate for a
* particular external link. This currently may include rel => nofollow
* (depending on configuration, namespace, and the URL's domain) and/or a
* target attribute (depending on configuration).
*
- * @param string|bool $url optional URL, to extract the domain from for rel =>
+ * @param string|bool $url Optional URL, to extract the domain from for rel =>
* nofollow if appropriate
- * @return Array associative array of HTML attributes
+ * @return array Associative array of HTML attributes
*/
- function getExternalLinkAttribs( $url = false ) {
+ public function getExternalLinkAttribs( $url = false ) {
$attribs = array();
$attribs['rel'] = self::getExternalLinkRel( $url, $this->mTitle );
@@ -1724,52 +1759,86 @@ class Parser {
}
/**
- * Replace unusual URL escape codes with their equivalent characters
- *
- * @param $url String
- * @return String
+ * Replace unusual escape codes in a URL with their equivalent characters
*
- * @todo This can merge genuinely required bits in the path or query string,
- * breaking legit URLs. A proper fix would treat the various parts of
- * the URL differently; as a workaround, just use the output for
- * statistical records, not for actual linking/output.
+ * @deprecated since 1.24, use normalizeLinkUrl
+ * @param string $url
+ * @return string
*/
- static function replaceUnusualEscapes( $url ) {
- return preg_replace_callback( '/%[0-9A-Fa-f]{2}/',
- array( __CLASS__, 'replaceUnusualEscapesCallback' ), $url );
+ public static function replaceUnusualEscapes( $url ) {
+ wfDeprecated( __METHOD__, '1.24' );
+ return self::normalizeLinkUrl( $url );
}
/**
- * Callback function used in replaceUnusualEscapes().
- * Replaces unusual URL escape codes with their equivalent character
+ * Replace unusual escape codes in a URL with their equivalent characters
*
- * @param $matches array
+ * This generally follows the syntax defined in RFC 3986, with special
+ * consideration for HTTP query strings.
*
+ * @param string $url
* @return string
*/
- private static function replaceUnusualEscapesCallback( $matches ) {
- $char = urldecode( $matches[0] );
- $ord = ord( $char );
- # Is it an unsafe or HTTP reserved character according to RFC 1738?
- if ( $ord > 32 && $ord < 127 && strpos( '<>"#{}|\^~[]`;/?', $char ) === false ) {
- # No, shouldn't be escaped
- return $char;
- } else {
- # Yes, leave it escaped
- return $matches[0];
+ public static function normalizeLinkUrl( $url ) {
+ # First, make sure unsafe characters are encoded
+ $url = preg_replace_callback( '/[\x00-\x20"<>\[\\\\\]^`{|}\x7F-\xFF]/',
+ function ( $m ) {
+ return rawurlencode( $m[0] );
+ },
+ $url
+ );
+
+ $ret = '';
+ $end = strlen( $url );
+
+ # Fragment part - 'fragment'
+ $start = strpos( $url, '#' );
+ if ( $start !== false && $start < $end ) {
+ $ret = self::normalizeUrlComponent(
+ substr( $url, $start, $end - $start ), '"#%<>[\]^`{|}' ) . $ret;
+ $end = $start;
}
+
+ # Query part - 'query' minus &=+;
+ $start = strpos( $url, '?' );
+ if ( $start !== false && $start < $end ) {
+ $ret = self::normalizeUrlComponent(
+ substr( $url, $start, $end - $start ), '"#%<>[\]^`{|}&=+;' ) . $ret;
+ $end = $start;
+ }
+
+ # Scheme and path part - 'pchar'
+ # (we assume no userinfo or encoded colons in the host)
+ $ret = self::normalizeUrlComponent(
+ substr( $url, 0, $end ), '"#%<>[\]^`{|}/?' ) . $ret;
+
+ return $ret;
+ }
+
+ private static function normalizeUrlComponent( $component, $unsafe ) {
+ $callback = function ( $matches ) use ( $unsafe ) {
+ $char = urldecode( $matches[0] );
+ $ord = ord( $char );
+ if ( $ord > 32 && $ord < 127 && strpos( $unsafe, $char ) === false ) {
+ # Unescape it
+ return $char;
+ } else {
+ # Leave it escaped, but use uppercase for a-f
+ return strtoupper( $matches[0] );
+ }
+ };
+ return preg_replace_callback( '/%[0-9A-Fa-f]{2}/', $callback, $component );
}
/**
* make an image if it's allowed, either through the global
* option, through the exception, or through the on-wiki whitelist
- * @private
*
- * $param $url string
+ * @param string $url
*
* @return string
*/
- function maybeMakeExternalImage( $url ) {
+ private function maybeMakeExternalImage( $url ) {
$imagesfrom = $this->mOptions->getAllowExternalImagesFrom();
$imagesexception = !empty( $imagesfrom );
$text = false;
@@ -1787,16 +1856,23 @@ class Parser {
} else {
$imagematch = false;
}
+
if ( $this->mOptions->getAllowExternalImages()
- || ( $imagesexception && $imagematch ) ) {
+ || ( $imagesexception && $imagematch )
+ ) {
if ( preg_match( self::EXT_IMAGE_REGEX, $url ) ) {
# Image found
$text = Linker::makeExternalImage( $url );
}
}
if ( !$text && $this->mOptions->getEnableImageWhitelist()
- && preg_match( self::EXT_IMAGE_REGEX, $url ) ) {
- $whitelist = explode( "\n", wfMessage( 'external_image_whitelist' )->inContentLanguage()->text() );
+ && preg_match( self::EXT_IMAGE_REGEX, $url )
+ ) {
+ $whitelist = explode(
+ "\n",
+ wfMessage( 'external_image_whitelist' )->inContentLanguage()->text()
+ );
+
foreach ( $whitelist as $entry ) {
# Sanitize the regex fragment, make it case-insensitive, ignore blank entries/comments
if ( strpos( $entry, '#' ) === 0 || $entry === '' ) {
@@ -1815,26 +1891,27 @@ class Parser {
/**
* Process [[ ]] wikilinks
*
- * @param $s string
+ * @param string $s
*
- * @return String: processed text
+ * @return string Processed text
*
* @private
*/
- function replaceInternalLinks( $s ) {
+ public function replaceInternalLinks( $s ) {
$this->mLinkHolders->merge( $this->replaceInternalLinks2( $s ) );
return $s;
}
/**
* Process [[ ]] wikilinks (RIL)
- * @param $s
+ * @param string $s
* @throws MWException
* @return LinkHolderArray
*
* @private
*/
- function replaceInternalLinks2( &$s ) {
+ public function replaceInternalLinks2( &$s ) {
+ global $wgExtraInterlanguageLinkPrefixes;
wfProfileIn( __METHOD__ );
wfProfileIn( __METHOD__ . '-setup' );
@@ -1863,7 +1940,9 @@ class Parser {
if ( $useLinkPrefixExtension ) {
# Match the end of a line for a word that's not followed by whitespace,
# e.g. in the case of 'The Arab al[[Razi]]', 'al' will be matched
- $e2 = wfMessage( 'linkprefix' )->inContentLanguage()->text();
+ global $wgContLang;
+ $charset = $wgContLang->linkPrefixCharset();
+ $e2 = "/^((?>.*[^$charset]|))(.+)$/sDu";
}
if ( is_null( $this->mTitle ) ) {
@@ -1887,8 +1966,11 @@ class Parser {
$useSubpages = $this->areSubpagesAllowed();
wfProfileOut( __METHOD__ . '-setup' );
+ // @codingStandardsIgnoreStart Squiz.WhiteSpace.SemicolonSpacing.Incorrect
# Loop for each link
for ( ; $line !== false && $line !== null; $a->next(), $line = $a->current() ) {
+ // @codingStandardsIgnoreStart
+
# Check for excessive memory usage
if ( $holders->isBig() ) {
# Too big
@@ -1926,11 +2008,10 @@ class Parser {
# Still some problems for cases where the ] is meant to be outside punctuation,
# and no image is in sight. See bug 2095.
#
- if ( $text !== '' &&
- substr( $m[3], 0, 1 ) === ']' &&
- strpos( $text, '[' ) !== false
- )
- {
+ if ( $text !== ''
+ && substr( $m[3], 0, 1 ) === ']'
+ && strpos( $text, '[' ) !== false
+ ) {
$text .= ']'; # so that replaceExternalLinks($text) works later
$m[3] = substr( $m[3], 1 );
}
@@ -1940,7 +2021,8 @@ class Parser {
$m[1] = str_replace( array( '<', '>' ), array( '&lt;', '&gt;' ), rawurldecode( $m[1] ) );
}
$trail = $m[3];
- } elseif ( preg_match( $e1_img, $line, $m ) ) { # Invalid, but might be an image with a link in its caption
+ } elseif ( preg_match( $e1_img, $line, $m ) ) {
+ # Invalid, but might be an image with a link in its caption
$might_be_img = true;
$text = $m[2];
if ( strpos( $m[1], '%' ) !== false ) {
@@ -1955,10 +2037,12 @@ class Parser {
wfProfileOut( __METHOD__ . "-e1" );
wfProfileIn( __METHOD__ . "-misc" );
+ $origLink = $m[1];
+
# Don't allow internal links to pages containing
# PROTO: where PROTO is a valid URL protocol; these
# should be external links.
- if ( preg_match( '/^(?i:' . $this->mUrlProtocols . ')/', $m[1] ) ) {
+ if ( preg_match( '/^(?i:' . $this->mUrlProtocols . ')/', $origLink ) ) {
$s .= $prefix . '[[' . $line;
wfProfileOut( __METHOD__ . "-misc" );
continue;
@@ -1966,12 +2050,12 @@ class Parser {
# Make subpage if necessary
if ( $useSubpages ) {
- $link = $this->maybeDoSubpageLink( $m[1], $text );
+ $link = $this->maybeDoSubpageLink( $origLink, $text );
} else {
- $link = $m[1];
+ $link = $origLink;
}
- $noforce = ( substr( $m[1], 0, 1 ) !== ':' );
+ $noforce = ( substr( $origLink, 0, 1 ) !== ':' );
if ( !$noforce ) {
# Strip off leading ':'
$link = substr( $link, 1 );
@@ -1987,7 +2071,7 @@ class Parser {
}
$ns = $nt->getNamespace();
- $iw = $nt->getInterWiki();
+ $iw = $nt->getInterwiki();
wfProfileOut( __METHOD__ . "-title" );
if ( $might_be_img ) { # if this is actually an invalid link
@@ -2047,12 +2131,15 @@ class Parser {
}
# Link not escaped by : , create the various objects
- if ( $noforce ) {
+ if ( $noforce && !$nt->wasLocalInterwiki() ) {
# Interwikis
wfProfileIn( __METHOD__ . "-interwiki" );
- if ( $iw && $this->mOptions->getInterwikiMagic() && $nottalk && Language::fetchLanguageName( $iw, null, 'mw' ) ) {
- // XXX: the above check prevents links to sites with identifiers that are not language codes
-
+ if (
+ $iw && $this->mOptions->getInterwikiMagic() && $nottalk && (
+ Language::fetchLanguageName( $iw, null, 'mw' ) ||
+ in_array( $iw, $wgExtraInterlanguageLinkPrefixes )
+ )
+ ) {
# Bug 24502: filter duplicates
if ( !isset( $this->mLangLinkLanguages[$iw] ) ) {
$this->mLangLinkLanguages[$iw] = true;
@@ -2108,7 +2195,6 @@ class Parser {
/**
* Strip the whitespace Category links produce, see bug 87
- * @todo We might want to use trim($tmp, "\n") here.
*/
$s .= trim( $prefix . $trail, "\n" ) == '' ? '' : $prefix . $trail;
@@ -2120,7 +2206,7 @@ class Parser {
# Self-link checking. For some languages, variants of the title are checked in
# LinkHolderArray::doVariants() to allow batching the existence checks necessary
# for linking to a different variant.
- if ( $ns != NS_SPECIAL && $nt->equals( $this->mTitle ) && $nt->getFragment() === '' ) {
+ if ( $ns != NS_SPECIAL && $nt->equals( $this->mTitle ) && !$nt->hasFragment() ) {
$s .= $prefix . Linker::makeSelfLinkObj( $nt, $text, '', $trail );
continue;
}
@@ -2169,14 +2255,14 @@ class Parser {
* breaking URLs in the following text without breaking trails on the
* wiki links, it's been made into a horrible function.
*
- * @param $nt Title
- * @param $text String
- * @param array $query or String
- * @param $trail String
- * @param $prefix String
- * @return String: HTML-wikitext mix oh yuck
+ * @param Title $nt
+ * @param string $text
+ * @param array|string $query
+ * @param string $trail
+ * @param string $prefix
+ * @return string HTML-wikitext mix oh yuck
*/
- function makeKnownLinkHolder( $nt, $text = '', $query = array(), $trail = '', $prefix = '' ) {
+ public function makeKnownLinkHolder( $nt, $text = '', $query = array(), $trail = '', $prefix = '' ) {
list( $inside, $trail ) = Linker::splitTrail( $trail );
if ( is_string( $query ) ) {
@@ -2198,19 +2284,19 @@ class Parser {
* Not needed quite as much as it used to be since free links are a bit
* more sensible these days. But bracketed links are still an issue.
*
- * @param string $text more-or-less HTML
- * @return String: less-or-more HTML with NOPARSE bits
+ * @param string $text More-or-less HTML
+ * @return string Less-or-more HTML with NOPARSE bits
*/
- function armorLinks( $text ) {
+ public function armorLinks( $text ) {
return preg_replace( '/\b((?i)' . $this->mUrlProtocols . ')/',
"{$this->mUniqPrefix}NOPARSE$1", $text );
}
/**
* Return true if subpage links should be expanded on this page.
- * @return Boolean
+ * @return bool
*/
- function areSubpagesAllowed() {
+ public function areSubpagesAllowed() {
# Some namespaces don't allow subpages
return MWNamespace::hasSubpages( $this->mTitle->getNamespace() );
}
@@ -2218,12 +2304,12 @@ class Parser {
/**
* Handle link to subpage if necessary
*
- * @param string $target the source of the link
- * @param &$text String: the link text, modified as necessary
- * @return string the full name of the link
+ * @param string $target The source of the link
+ * @param string &$text The link text, modified as necessary
+ * @return string The full name of the link
* @private
*/
- function maybeDoSubpageLink( $target, &$text ) {
+ public function maybeDoSubpageLink( $target, &$text ) {
return Linker::normalizeSubpageLink( $this->mTitle, $target, $text );
}
@@ -2233,7 +2319,7 @@ class Parser {
*
* @return string
*/
- function closeParagraph() {
+ public function closeParagraph() {
$result = '';
if ( $this->mLastSection != '' ) {
$result = '</' . $this->mLastSection . ">\n";
@@ -2248,12 +2334,12 @@ class Parser {
* of both arguments, starting at the beginning of both.
* @private
*
- * @param $st1 string
- * @param $st2 string
+ * @param string $st1
+ * @param string $st2
*
* @return int
*/
- function getCommon( $st1, $st2 ) {
+ public function getCommon( $st1, $st2 ) {
$fl = strlen( $st1 );
$shorter = strlen( $st2 );
if ( $fl < $shorter ) {
@@ -2273,21 +2359,21 @@ class Parser {
* element appropriate to the prefix character passed into them.
* @private
*
- * @param $char string
+ * @param string $char
*
* @return string
*/
- function openList( $char ) {
+ public function openList( $char ) {
$result = $this->closeParagraph();
if ( '*' === $char ) {
- $result .= "<ul>\n<li>";
+ $result .= "<ul><li>";
} elseif ( '#' === $char ) {
- $result .= "<ol>\n<li>";
+ $result .= "<ol><li>";
} elseif ( ':' === $char ) {
- $result .= "<dl>\n<dd>";
+ $result .= "<dl><dd>";
} elseif ( ';' === $char ) {
- $result .= "<dl>\n<dt>";
+ $result .= "<dl><dt>";
$this->mDTopen = true;
} else {
$result = '<!-- ERR 1 -->';
@@ -2298,12 +2384,12 @@ class Parser {
/**
* TODO: document
- * @param $char String
+ * @param string $char
* @private
*
* @return string
*/
- function nextItem( $char ) {
+ public function nextItem( $char ) {
if ( '*' === $char || '#' === $char ) {
return "</li>\n<li>";
} elseif ( ':' === $char || ';' === $char ) {
@@ -2323,40 +2409,40 @@ class Parser {
}
/**
- * TODO: document
- * @param $char String
+ * @todo Document
+ * @param string $char
* @private
*
* @return string
*/
- function closeList( $char ) {
+ public function closeList( $char ) {
if ( '*' === $char ) {
- $text = "</li>\n</ul>";
+ $text = "</li></ul>";
} elseif ( '#' === $char ) {
- $text = "</li>\n</ol>";
+ $text = "</li></ol>";
} elseif ( ':' === $char ) {
if ( $this->mDTopen ) {
$this->mDTopen = false;
- $text = "</dt>\n</dl>";
+ $text = "</dt></dl>";
} else {
- $text = "</dd>\n</dl>";
+ $text = "</dd></dl>";
}
} else {
return '<!-- ERR 3 -->';
}
- return $text . "\n";
+ return $text;
}
/**#@-*/
/**
* Make lists from lines starting with ':', '*', '#', etc. (DBL)
*
- * @param $text String
- * @param $linestart Boolean: whether or not this is at the start of a line.
+ * @param string $text
+ * @param bool $linestart Whether or not this is at the start of a line.
* @private
- * @return string the lists rendered as HTML
+ * @return string The lists rendered as HTML
*/
- function doBlockLevels( $text, $linestart ) {
+ public function doBlockLevels( $text, $linestart ) {
wfProfileIn( __METHOD__ );
# Parsing through the text line by line. The main thing
@@ -2442,6 +2528,9 @@ class Parser {
}
# Open prefixes where appropriate.
+ if ( $lastPrefix && $prefixLength > $commonPrefixLength ) {
+ $output .= "\n";
+ }
while ( $prefixLength > $commonPrefixLength ) {
$char = substr( $prefix, $commonPrefixLength, 1 );
$output .= $this->openList( $char );
@@ -2455,6 +2544,9 @@ class Parser {
}
++$commonPrefixLength;
}
+ if ( !$prefixLength && $lastPrefix ) {
+ $output .= "\n";
+ }
$lastPrefix = $prefix2;
}
@@ -2463,13 +2555,22 @@ class Parser {
wfProfileIn( __METHOD__ . "-paragraph" );
# No prefix (not in list)--go to paragraph mode
# XXX: use a stack for nestable elements like span, table and div
- $openmatch = preg_match( '/(?:<table|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|<p|<ul|<ol|<dl|<li|<\\/tr|<\\/td|<\\/th)/iS', $t );
+ $openmatch = preg_match(
+ '/(?:<table|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|'
+ . '<p|<ul|<ol|<dl|<li|<\\/tr|<\\/td|<\\/th)/iS',
+ $t
+ );
$closematch = preg_match(
- '/(?:<\\/table|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|' .
- '<td|<th|<\\/?blockquote|<\\/?div|<hr|<\\/pre|<\\/p|<\\/mw:|' . $this->mUniqPrefix . '-pre|<\\/li|<\\/ul|<\\/ol|<\\/dl|<\\/?center)/iS', $t );
+ '/(?:<\\/table|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|'
+ . '<td|<th|<\\/?blockquote|<\\/?div|<hr|<\\/pre|<\\/p|<\\/mw:|'
+ . $this->mUniqPrefix
+ . '-pre|<\\/li|<\\/ul|<\\/ol|<\\/dl|<\\/?center)/iS',
+ $t
+ );
+
if ( $openmatch or $closematch ) {
$paragraphStack = false;
- # TODO bug 5718: paragraph closed
+ # @todo bug 5718: paragraph closed
$output .= $this->closeParagraph();
if ( $preOpenMatch and !$preCloseMatch ) {
$this->mInPre = true;
@@ -2481,7 +2582,10 @@ class Parser {
}
$inBlockElem = !$closematch;
} elseif ( !$inBlockElem && !$this->mInPre ) {
- if ( ' ' == substr( $t, 0, 1 ) and ( $this->mLastSection === 'pre' || trim( $t ) != '' ) and !$inBlockquote ) {
+ if ( ' ' == substr( $t, 0, 1 )
+ && ( $this->mLastSection === 'pre' || trim( $t ) != '' )
+ && !$inBlockquote
+ ) {
# pre
if ( $this->mLastSection !== 'pre' ) {
$paragraphStack = false;
@@ -2524,12 +2628,18 @@ class Parser {
$this->mInPre = false;
}
if ( $paragraphStack === false ) {
- $output .= $t . "\n";
+ $output .= $t;
+ if ( $prefixLength === 0 ) {
+ $output .= "\n";
+ }
}
}
while ( $prefixLength ) {
$output .= $this->closeList( $prefix2[$prefixLength - 1] );
--$prefixLength;
+ if ( !$prefixLength ) {
+ $output .= "\n";
+ }
}
if ( $this->mLastSection != '' ) {
$output .= '</' . $this->mLastSection . '>';
@@ -2544,13 +2654,13 @@ class Parser {
* Split up a string on ':', ignoring any occurrences inside tags
* to prevent illegal overlapping.
*
- * @param string $str the string to split
- * @param &$before String set to everything before the ':'
- * @param &$after String set to everything after the ':'
+ * @param string $str The string to split
+ * @param string &$before Set to everything before the ':'
+ * @param string &$after Set to everything after the ':'
* @throws MWException
- * @return String the position of the ':', or false if none found
+ * @return string The position of the ':', or false if none found
*/
- function findColonNoLinks( $str, &$before, &$after ) {
+ public function findColonNoLinks( $str, &$before, &$after ) {
wfProfileIn( __METHOD__ );
$pos = strpos( $str, ':' );
@@ -2712,14 +2822,14 @@ class Parser {
*
* @private
*
- * @param $index integer
- * @param bool|\PPFrame $frame
+ * @param int $index
+ * @param bool|PPFrame $frame
*
* @throws MWException
* @return string
*/
- function getVariableValue( $index, $frame = false ) {
- global $wgContLang, $wgSitename, $wgServer;
+ public function getVariableValue( $index, $frame = false ) {
+ global $wgContLang, $wgSitename, $wgServer, $wgServerName;
global $wgArticlePath, $wgScriptPath, $wgStylePath;
if ( is_null( $this->mTitle ) ) {
@@ -2747,6 +2857,9 @@ class Parser {
$pageLang = $this->getFunctionLang();
switch ( $index ) {
+ case '!':
+ $value = '|';
+ break;
case 'currentmonth':
$value = $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'm' ) );
break;
@@ -2811,13 +2924,21 @@ class Parser {
$value = wfEscapeWikiText( $this->mTitle->getRootText() );
break;
case 'rootpagenamee':
- $value = wfEscapeWikiText( wfUrlEncode( str_replace( ' ', '_', $this->mTitle->getRootText() ) ) );
+ $value = wfEscapeWikiText( wfUrlEncode( str_replace(
+ ' ',
+ '_',
+ $this->mTitle->getRootText()
+ ) ) );
break;
case 'basepagename':
$value = wfEscapeWikiText( $this->mTitle->getBaseText() );
break;
case 'basepagenamee':
- $value = wfEscapeWikiText( wfUrlEncode( str_replace( ' ', '_', $this->mTitle->getBaseText() ) ) );
+ $value = wfEscapeWikiText( wfUrlEncode( str_replace(
+ ' ',
+ '_',
+ $this->mTitle->getBaseText()
+ ) ) );
break;
case 'talkpagename':
if ( $this->mTitle->canTalk() ) {
@@ -2928,7 +3049,9 @@ class Parser {
$value = $this->mTitle->getNamespace();
break;
case 'talkspace':
- $value = $this->mTitle->canTalk() ? str_replace( '_', ' ', $this->mTitle->getTalkNsText() ) : '';
+ $value = $this->mTitle->canTalk()
+ ? str_replace( '_', ' ', $this->mTitle->getTalkNsText() )
+ : '';
break;
case 'talkspacee':
$value = $this->mTitle->canTalk() ? wfUrlencode( $this->mTitle->getTalkNsText() ) : '';
@@ -2940,7 +3063,7 @@ class Parser {
$value = ( wfUrlencode( $this->mTitle->getSubjectNsText() ) );
break;
case 'currentdayname':
- $value = $pageLang->getWeekdayName( MWTimestamp::getInstance( $ts )->format( 'w' ) + 1 );
+ $value = $pageLang->getWeekdayName( (int)MWTimestamp::getInstance( $ts )->format( 'w' ) + 1 );
break;
case 'currentyear':
$value = $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'Y' ), true );
@@ -2960,13 +3083,19 @@ class Parser {
$value = $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'w' ) );
break;
case 'localdayname':
- $value = $pageLang->getWeekdayName( MWTimestamp::getLocalInstance( $ts )->format( 'w' ) + 1 );
+ $value = $pageLang->getWeekdayName(
+ (int)MWTimestamp::getLocalInstance( $ts )->format( 'w' ) + 1
+ );
break;
case 'localyear':
$value = $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'Y' ), true );
break;
case 'localtime':
- $value = $pageLang->time( MWTimestamp::getLocalInstance( $ts )->format( 'YmdHis' ), false, false );
+ $value = $pageLang->time(
+ MWTimestamp::getLocalInstance( $ts )->format( 'YmdHis' ),
+ false,
+ false
+ );
break;
case 'localhour':
$value = $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'H' ), true );
@@ -3020,8 +3149,7 @@ class Parser {
case 'server':
return $wgServer;
case 'servername':
- $serverParts = wfParseUrl( $wgServer );
- return $serverParts && isset( $serverParts['host'] ) ? $serverParts['host'] : $wgServer;
+ return $wgServerName;
case 'scriptpath':
return $wgScriptPath;
case 'stylepath':
@@ -3031,13 +3159,17 @@ class Parser {
case 'contentlanguage':
global $wgLanguageCode;
return $wgLanguageCode;
+ case 'cascadingsources':
+ $value = CoreParserFunctions::cascadingsources( $this );
+ break;
default:
$ret = null;
- if ( wfRunHooks( 'ParserGetVariableValueSwitch', array( &$this, &$this->mVarCache, &$index, &$ret, &$frame ) ) ) {
- return $ret;
- } else {
- return null;
- }
+ wfRunHooks(
+ 'ParserGetVariableValueSwitch',
+ array( &$this, &$this->mVarCache, &$index, &$ret, &$frame )
+ );
+
+ return $ret;
}
if ( $index ) {
@@ -3052,7 +3184,7 @@ class Parser {
*
* @private
*/
- function initialiseVariables() {
+ public function initialiseVariables() {
wfProfileIn( __METHOD__ );
$variableIDs = MagicWord::getVariableIDs();
$substIDs = MagicWord::getSubstIDs();
@@ -3067,9 +3199,9 @@ class Parser {
* This is the ghost of replace_variables().
*
* @param string $text The text to parse
- * @param $flags Integer: bitwise combination of:
- * self::PTD_FOR_INCLUSION Handle "<noinclude>" and "<includeonly>" as if the text is being
- * included. Default is to assume a direct page view.
+ * @param int $flags Bitwise combination of:
+ * - self::PTD_FOR_INCLUSION: Handle "<noinclude>" and "<includeonly>" as if the text is being
+ * included. Default is to assume a direct page view.
*
* The generated DOM tree must depend only on the input text and the flags.
* The DOM tree must be the same in OT_HTML and OT_WIKI mode, to avoid a regression of bug 4899.
@@ -3082,11 +3214,9 @@ class Parser {
* cache may be implemented at a later date which takes further advantage of these strict
* dependency requirements.
*
- * @private
- *
* @return PPNode
*/
- function preprocessToDom( $text, $flags = 0 ) {
+ public function preprocessToDom( $text, $flags = 0 ) {
$dom = $this->getPreprocessor()->preprocessToObj( $text, $flags );
return $dom;
}
@@ -3094,7 +3224,7 @@ class Parser {
/**
* Return a three-element array: leading whitespace, string contents, trailing whitespace
*
- * @param $s string
+ * @param string $s
*
* @return array
*/
@@ -3121,16 +3251,17 @@ class Parser {
* self::OT_PREPROCESS: templates but not extension tags
* self::OT_HTML: all templates and extension tags
*
- * @param string $text the text to transform
- * @param $frame PPFrame Object describing the arguments passed to the template.
- * Arguments may also be provided as an associative array, as was the usual case before MW1.12.
- * Providing arguments this way may be useful for extensions wishing to perform variable replacement explicitly.
- * @param $argsOnly Boolean only do argument (triple-brace) expansion, not double-brace expansion
- * @private
- *
+ * @param string $text The text to transform
+ * @param bool|PPFrame $frame Object describing the arguments passed to the
+ * template. Arguments may also be provided as an associative array, as
+ * was the usual case before MW1.12. Providing arguments this way may be
+ * useful for extensions wishing to perform variable replacement
+ * explicitly.
+ * @param bool $argsOnly Only do argument (triple-brace) expansion, not
+ * double-brace expansion.
* @return string
*/
- function replaceVariables( $text, $frame = false, $argsOnly = false ) {
+ public function replaceVariables( $text, $frame = false, $argsOnly = false ) {
# Is there any text? Also, Prevent too big inclusions!
if ( strlen( $text ) < 1 || strlen( $text ) > $this->mOptions->getMaxIncludeSize() ) {
return $text;
@@ -3140,7 +3271,8 @@ class Parser {
if ( $frame === false ) {
$frame = $this->getPreprocessor()->newFrame();
} elseif ( !( $frame instanceof PPFrame ) ) {
- wfDebug( __METHOD__ . " called using plain parameters instead of a PPFrame instance. Creating custom frame.\n" );
+ wfDebug( __METHOD__ . " called using plain parameters instead of "
+ . "a PPFrame instance. Creating custom frame.\n" );
$frame = $this->getPreprocessor()->newCustomFrame( $frame );
}
@@ -3155,11 +3287,11 @@ class Parser {
/**
* Clean up argument array - refactored in 1.9 so parserfunctions can use it, too.
*
- * @param $args array
+ * @param array $args
*
* @return array
*/
- static function createAssocArgs( $args ) {
+ public static function createAssocArgs( $args ) {
$assocArgs = array();
$index = 1;
foreach ( $args as $arg ) {
@@ -3185,7 +3317,7 @@ class Parser {
* Warn the user when a parser limitation is reached
* Will warn at most once the user per limitation type
*
- * @param string $limitationType should be one of:
+ * @param string $limitationType Should be one of:
* 'expensive-parserfunction' (corresponding messages:
* 'expensive-parserfunction-warning',
* 'expensive-parserfunction-category')
@@ -3201,11 +3333,11 @@ class Parser {
* 'expansion-depth-exceeded' (corresponding messages:
* 'expansion-depth-exceeded-warning',
* 'expansion-depth-exceeded-category')
- * @param int|null $current Current value
- * @param int|null $max Maximum allowed, when an explicit limit has been
+ * @param string|int|null $current Current value
+ * @param string|int|null $max Maximum allowed, when an explicit limit has been
* exceeded, provide the values (optional)
*/
- function limitationWarn( $limitationType, $current = '', $max = '' ) {
+ public function limitationWarn( $limitationType, $current = '', $max = '' ) {
# does no harm if $current and $max are present but are unnecessary for the message
$warning = wfMessage( "$limitationType-warning" )->numParams( $current, $max )
->inLanguage( $this->mOptions->getUserLangObj() )->text();
@@ -3217,26 +3349,32 @@ class Parser {
* Return the text of a template, after recursively
* replacing any variables or templates within the template.
*
- * @param array $piece the parts of the template
- * $piece['title']: the title, i.e. the part before the |
- * $piece['parts']: the parameter array
- * $piece['lineStart']: whether the brace was at the start of a line
- * @param $frame PPFrame The current frame, contains template arguments
- * @throws MWException
- * @return String: the text of the template
- * @private
+ * @param array $piece The parts of the template
+ * $piece['title']: the title, i.e. the part before the |
+ * $piece['parts']: the parameter array
+ * $piece['lineStart']: whether the brace was at the start of a line
+ * @param PPFrame $frame The current frame, contains template arguments
+ * @throws Exception
+ * @return string The text of the template
*/
- function braceSubstitution( $piece, $frame ) {
+ public function braceSubstitution( $piece, $frame ) {
wfProfileIn( __METHOD__ );
wfProfileIn( __METHOD__ . '-setup' );
- # Flags
- $found = false; # $text has been filled
- $nowiki = false; # wiki markup in $text should be escaped
- $isHTML = false; # $text is HTML, armour it against wikitext transformation
- $forceRawInterwiki = false; # Force interwiki transclusion to be done in raw mode not rendered
- $isChildObj = false; # $text is a DOM node needing expansion in a child frame
- $isLocalObj = false; # $text is a DOM node needing expansion in the current frame
+ // Flags
+
+ // $text has been filled
+ $found = false;
+ // wiki markup in $text should be escaped
+ $nowiki = false;
+ // $text is HTML, armour it against wikitext transformation
+ $isHTML = false;
+ // Force interwiki transclusion to be done in raw mode not rendered
+ $forceRawInterwiki = false;
+ // $text is a DOM node needing expansion in a child frame
+ $isChildObj = false;
+ // $text is a DOM node needing expansion in the current frame
+ $isLocalObj = false;
# Title object, where $text came from
$title = false;
@@ -3251,7 +3389,8 @@ class Parser {
$originalTitle = $part1;
# $args is a list of argument nodes, starting from index 0, not including $part1
- # @todo FIXME: If piece['parts'] is null then the call to getLength() below won't work b/c this $args isn't an object
+ # @todo FIXME: If piece['parts'] is null then the call to getLength()
+ # below won't work b/c this $args isn't an object
$args = ( null == $piece['parts'] ) ? array() : $piece['parts'];
wfProfileOut( __METHOD__ . '-setup' );
@@ -3385,13 +3524,14 @@ class Parser {
if ( !$title->isExternal() ) {
if ( $title->isSpecialPage()
&& $this->mOptions->getAllowSpecialInclusion()
- && $this->ot['html'] )
- {
+ && $this->ot['html']
+ ) {
// Pass the template arguments as URL parameters.
// "uselang" will have no effect since the Language object
// is forced to the one defined in ParserOptions.
$pageArgs = array();
- for ( $i = 0; $i < $args->getLength(); $i++ ) {
+ $argsLength = $args->getLength();
+ for ( $i = 0; $i < $argsLength; $i++ ) {
$bits = $args->item( $i )->splitArg();
if ( strval( $bits['index'] ) === '' ) {
$name = trim( $frame->expand( $bits['name'], PPFrame::STRIP_COMMENTS ) );
@@ -3416,7 +3556,8 @@ class Parser {
}
} elseif ( MWNamespace::isNonincludable( $title->getNamespace() ) ) {
$found = false; # access denied
- wfDebug( __METHOD__ . ": template inclusion denied for " . $title->getPrefixedDBkey() );
+ wfDebug( __METHOD__ . ": template inclusion denied for " .
+ $title->getPrefixedDBkey() . "\n" );
} else {
list( $text, $title ) = $this->getTemplateDom( $title );
if ( $text !== false ) {
@@ -3476,12 +3617,7 @@ class Parser {
$text = $newFrame->expand( $text, PPFrame::RECOVER_ORIG );
} elseif ( $titleText !== false && $newFrame->isEmpty() ) {
# Expansion is eligible for the empty-frame cache
- if ( isset( $this->mTplExpandCache[$titleText] ) ) {
- $text = $this->mTplExpandCache[$titleText];
- } else {
- $text = $newFrame->expand( $text );
- $this->mTplExpandCache[$titleText] = $text;
- }
+ $text = $newFrame->cachedExpand( $titleText, $text );
} else {
# Uncached expansion
$text = $newFrame->expand( $text );
@@ -3504,8 +3640,8 @@ class Parser {
$text = wfEscapeWikiText( $text );
} elseif ( is_string( $text )
&& !$piece['lineStart']
- && preg_match( '/^(?:{\\||:|;|#|\*)/', $text ) )
- {
+ && preg_match( '/^(?:{\\||:|;|#|\*)/', $text )
+ ) {
# Bug 529: if the template begins with a table or block-level
# element, it should be treated as beginning a new line.
# This behavior is somewhat controversial.
@@ -3523,7 +3659,8 @@ class Parser {
preg_replace( '/^:/', '', $originalTitle );
$text = "[[:$originalTitle]]";
}
- $text .= $this->insertStripItem( '<!-- WARNING: template omitted, post-expand include size too large -->' );
+ $text .= $this->insertStripItem( '<!-- WARNING: template omitted, '
+ . 'post-expand include size too large -->' );
$this->limitationWarn( 'post-expand-template-inclusion' );
}
@@ -3550,9 +3687,10 @@ class Parser {
* nowiki: bool, wiki markup in $text should be escaped
*
* @since 1.21
- * @param $frame PPFrame The current frame, contains template arguments
- * @param $function string Function name
- * @param $args array Arguments to the function
+ * @param PPFrame $frame The current frame, contains template arguments
+ * @param string $function Function name
+ * @param array $args Arguments to the function
+ * @throws MWException
* @return array
*/
public function callParserFunction( $frame, $function, array $args = array() ) {
@@ -3655,11 +3793,11 @@ class Parser {
* Get the semi-parsed DOM representation of a template with a given title,
* and its redirect destination title. Cached.
*
- * @param $title Title
+ * @param Title $title
*
* @return array
*/
- function getTemplateDom( $title ) {
+ public function getTemplateDom( $title ) {
$cacheTitle = $title;
$titleText = $title->getPrefixedDBkey();
@@ -3694,10 +3832,11 @@ class Parser {
/**
* Fetch the unparsed text of a template and register a reference to it.
* @param Title $title
- * @return Array ( string or false, Title )
+ * @return array ( string or false, Title )
*/
- function fetchTemplateAndTitle( $title ) {
- $templateCb = $this->mOptions->getTemplateCallback(); # Defaults to Parser::statelessFetchTemplate()
+ public function fetchTemplateAndTitle( $title ) {
+ // Defaults to Parser::statelessFetchTemplate()
+ $templateCb = $this->mOptions->getTemplateCallback();
$stuff = call_user_func( $templateCb, $title, $this );
$text = $stuff['text'];
$finalTitle = isset( $stuff['finalTitle'] ) ? $stuff['finalTitle'] : $title;
@@ -3717,9 +3856,9 @@ class Parser {
/**
* Fetch the unparsed text of a template and register a reference to it.
* @param Title $title
- * @return mixed string or false
+ * @return string|bool
*/
- function fetchTemplate( $title ) {
+ public function fetchTemplate( $title ) {
$rv = $this->fetchTemplateAndTitle( $title );
return $rv[0];
}
@@ -3728,12 +3867,12 @@ class Parser {
* Static function to get a template
* Can be overridden via ParserOptions::setTemplateCallback().
*
- * @param $title Title
- * @param $parser Parser
+ * @param Title $title
+ * @param bool|Parser $parser
*
* @return array
*/
- static function statelessFetchTemplate( $title, $parser = false ) {
+ public static function statelessFetchTemplate( $title, $parser = false ) {
$text = $skip = false;
$finalTitle = $title;
$deps = array();
@@ -3817,7 +3956,7 @@ class Parser {
* @param array $options Array of options to RepoGroup::findFile
* @return File|bool
*/
- function fetchFile( $title, $options = array() ) {
+ public function fetchFile( $title, $options = array() ) {
$res = $this->fetchFileAndTitle( $title, $options );
return $res[0];
}
@@ -3827,9 +3966,9 @@ class Parser {
* If 'broken' is a key in $options then the file will appear as a broken thumbnail.
* @param Title $title
* @param array $options Array of options to RepoGroup::findFile
- * @return Array ( File or false, Title of file )
+ * @return array ( File or false, Title of file )
*/
- function fetchFileAndTitle( $title, $options = array() ) {
+ public function fetchFileAndTitle( $title, $options = array() ) {
$file = $this->fetchFileNoRegister( $title, $options );
$time = $file ? $file->getTimestamp() : false;
@@ -3839,12 +3978,7 @@ class Parser {
if ( $file && !$title->equals( $file->getTitle() ) ) {
# Update fetched file title
$title = $file->getTitle();
- if ( is_null( $file->getRedirectedTitle() ) ) {
- # This file was not a redirect, but the title does not match.
- # Register under the new name because otherwise the link will
- # get lost.
- $this->mOutput->addImage( $title->getDBkey(), $time, $sha1 );
- }
+ $this->mOutput->addImage( $title->getDBkey(), $time, $sha1 );
}
return array( $file, $title );
}
@@ -3857,7 +3991,7 @@ class Parser {
*
* @param Title $title
* @param array $options Array of options to RepoGroup::findFile
- * @return File or false
+ * @return File|bool
*/
protected function fetchFileNoRegister( $title, $options = array() ) {
if ( isset( $options['broken'] ) ) {
@@ -3873,12 +4007,12 @@ class Parser {
/**
* Transclude an interwiki link.
*
- * @param $title Title
- * @param $action
+ * @param Title $title
+ * @param string $action
*
* @return string
*/
- function interwikiTransclude( $title, $action ) {
+ public function interwikiTransclude( $title, $action ) {
global $wgEnableScaryTranscluding;
if ( !$wgEnableScaryTranscluding ) {
@@ -3894,10 +4028,10 @@ class Parser {
}
/**
- * @param $url string
- * @return Mixed|String
+ * @param string $url
+ * @return mixed|string
*/
- function fetchScaryTemplateMaybeFromCache( $url ) {
+ public function fetchScaryTemplateMaybeFromCache( $url ) {
global $wgTranscludeCacheExpiry;
$dbr = wfGetDB( DB_SLAVE );
$tsCond = $dbr->timestamp( time() - $wgTranscludeCacheExpiry );
@@ -3911,8 +4045,10 @@ class Parser {
$status = $req->execute(); // Status object
if ( $status->isOK() ) {
$text = $req->getContent();
- } elseif ( $req->getStatus() != 200 ) { // Though we failed to fetch the content, this status is useless.
- return wfMessage( 'scarytranscludefailed-httpstatus', $url, $req->getStatus() /* HTTP status */ )->inContentLanguage()->text();
+ } elseif ( $req->getStatus() != 200 ) {
+ // Though we failed to fetch the content, this status is useless.
+ return wfMessage( 'scarytranscludefailed-httpstatus' )
+ ->params( $url, $req->getStatus() /* HTTP status */ )->inContentLanguage()->text();
} else {
return wfMessage( 'scarytranscludefailed', $url )->inContentLanguage()->text();
}
@@ -3930,12 +4066,12 @@ class Parser {
* Triple brace replacement -- used for template arguments
* @private
*
- * @param $piece array
- * @param $frame PPFrame
+ * @param array $piece
+ * @param PPFrame $frame
*
* @return array
*/
- function argSubstitution( $piece, $frame ) {
+ public function argSubstitution( $piece, $frame ) {
wfProfileIn( __METHOD__ );
$error = false;
@@ -3945,11 +4081,10 @@ class Parser {
$object = false;
$text = $frame->getArgument( $argName );
if ( $text === false && $parts->getLength() > 0
- && (
- $this->ot['html']
- || $this->ot['pre']
- || ( $this->ot['wiki'] && $frame->isTemplate() )
- )
+ && ( $this->ot['html']
+ || $this->ot['pre']
+ || ( $this->ot['wiki'] && $frame->isTemplate() )
+ )
) {
# No match in frame, use the supplied default
$object = $parts->item( 0 )->getChildren();
@@ -3986,16 +4121,17 @@ class Parser {
* attributes Optional associative array of parsed attributes
* inner Contents of extension element
* noClose Original text did not have a close tag
- * @param $frame PPFrame
+ * @param PPFrame $frame
*
* @throws MWException
* @return string
*/
- function extensionSubstitution( $params, $frame ) {
+ public function extensionSubstitution( $params, $frame ) {
$name = $frame->expand( $params['name'] );
$attrText = !isset( $params['attr'] ) ? null : $frame->expand( $params['attr'] );
$content = !isset( $params['inner'] ) ? null : $frame->expand( $params['inner'] );
- $marker = "{$this->mUniqPrefix}-$name-" . sprintf( '%08X', $this->mMarkerIndex++ ) . self::MARKER_SUFFIX;
+ $marker = "{$this->mUniqPrefix}-$name-"
+ . sprintf( '%08X', $this->mMarkerIndex++ ) . self::MARKER_SUFFIX;
$isFunctionTag = isset( $this->mFunctionTagHooks[strtolower( $name )] ) &&
( $this->ot['html'] || $this->ot['pre'] );
@@ -4070,11 +4206,11 @@ class Parser {
/**
* Increment an include size counter
*
- * @param string $type the type of expansion
- * @param $size Integer: the size of the text
- * @return Boolean: false if this inclusion would take it over the maximum, true otherwise
+ * @param string $type The type of expansion
+ * @param int $size The size of the text
+ * @return bool False if this inclusion would take it over the maximum, true otherwise
*/
- function incrementIncludeSize( $type, $size ) {
+ public function incrementIncludeSize( $type, $size ) {
if ( $this->mIncludeSizes[$type] + $size > $this->mOptions->getMaxIncludeSize() ) {
return false;
} else {
@@ -4086,9 +4222,9 @@ class Parser {
/**
* Increment the expensive function count
*
- * @return Boolean: false if the limit has been exceeded
+ * @return bool False if the limit has been exceeded
*/
- function incrementExpensiveFunctionCount() {
+ public function incrementExpensiveFunctionCount() {
$this->mExpensiveFunctionCount++;
return $this->mExpensiveFunctionCount <= $this->mOptions->getExpensiveParserFunctionLimit();
}
@@ -4097,11 +4233,11 @@ class Parser {
* Strip double-underscore items like __NOGALLERY__ and __NOTOC__
* Fills $this->mDoubleUnderscores, returns the modified text
*
- * @param $text string
+ * @param string $text
*
* @return string
*/
- function doDoubleUnderscore( $text ) {
+ public function doDoubleUnderscore( $text ) {
wfProfileIn( __METHOD__ );
# The position of __TOC__ needs to be recorded
@@ -4127,7 +4263,9 @@ class Parser {
if ( isset( $this->mDoubleUnderscores['notoc'] ) && !$this->mForceTocPosition ) {
$this->mShowToc = false;
}
- if ( isset( $this->mDoubleUnderscores['hiddencat'] ) && $this->mTitle->getNamespace() == NS_CATEGORY ) {
+ if ( isset( $this->mDoubleUnderscores['hiddencat'] )
+ && $this->mTitle->getNamespace() == NS_CATEGORY
+ ) {
$this->addTrackingCategory( 'hidden-category-category' );
}
# (bug 8068) Allow control over whether robots index a page.
@@ -4156,8 +4294,12 @@ class Parser {
* Add a tracking category, getting the title from a system message,
* or print a debug message if the title is invalid.
*
- * @param string $msg message key
- * @return Boolean: whether the addition was successful
+ * Please add any message that you use with this function to
+ * $wgTrackingCategories. That way they will be listed on
+ * Special:TrackingCategories.
+ *
+ * @param string $msg Message key
+ * @return bool Whether the addition was successful
*/
public function addTrackingCategory( $msg ) {
if ( $this->mTitle->getNamespace() === NS_SPECIAL ) {
@@ -4195,13 +4337,13 @@ class Parser {
* It loops through all headlines, collects the necessary data, then splits up the
* string and re-inserts the newly formatted headlines.
*
- * @param $text String
- * @param string $origText original, untouched wikitext
- * @param $isMain Boolean
+ * @param string $text
+ * @param string $origText Original, untouched wikitext
+ * @param bool $isMain
* @return mixed|string
* @private
*/
- function formatHeadings( $text, $origText, $isMain = true ) {
+ public function formatHeadings( $text, $origText, $isMain = true ) {
global $wgMaxTocLevel, $wgExperimentalHtmlIds;
# Inhibit editsection links if requested in the page
@@ -4218,7 +4360,11 @@ class Parser {
# Get all headlines for numbering them and adding funky stuff like [edit]
# links - this is for later, but we need the number of headlines right now
$matches = array();
- $numMatches = preg_match_all( '/<H(?P<level>[1-6])(?P<attrib>.*?' . '>)\s*(?P<header>[\s\S]*?)\s*<\/H[1-6] *>/i', $text, $matches );
+ $numMatches = preg_match_all(
+ '/<H(?P<level>[1-6])(?P<attrib>.*?' . '>)\s*(?P<header>[\s\S]*?)\s*<\/H[1-6] *>/i',
+ $text,
+ $matches
+ );
# if there are fewer than 4 headlines in the article, do not show TOC
# unless it's been explicitly enabled.
@@ -4367,7 +4513,10 @@ class Parser {
# We strip any parameter from accepted tags (second regex), except dir="rtl|ltr" from <span>,
# to allow setting directionality in toc items.
$tocline = preg_replace(
- array( '#<(?!/?(span|sup|sub|i|b)(?: [^>]*)?>).*?' . '>#', '#<(/?(?:span(?: dir="(?:rtl|ltr)")?|sup|sub|i|b))(?: .*?)?' . '>#' ),
+ array(
+ '#<(?!/?(span|sup|sub|i|b)(?: [^>]*)?>).*?' . '>#',
+ '#<(/?(?:span(?: dir="(?:rtl|ltr)")?|sup|sub|i|b))(?: .*?)?' . '>#'
+ ),
array( '', '<$1>' ),
$safeHeadline
);
@@ -4431,7 +4580,11 @@ class Parser {
# Don't number the heading if it is the only one (looks silly)
if ( count( $matches[3] ) > 1 && $this->mOptions->getNumberHeadings() ) {
# the two are different if the line contains a link
- $headline = Html::element( 'span', array( 'class' => 'mw-headline-number' ), $numbering ) . ' ' . $headline;
+ $headline = Html::element(
+ 'span',
+ array( 'class' => 'mw-headline-number' ),
+ $numbering
+ ) . ' ' . $headline;
}
# Create the anchor for linking from the TOC to the section
@@ -4479,21 +4632,30 @@ class Parser {
if ( $isTemplate ) {
# Put a T flag in the section identifier, to indicate to extractSections()
# that sections inside <includeonly> should be counted.
- $editlinkArgs = array( $titleText, "T-$sectionIndex"/*, null */ );
+ $editsectionPage = $titleText;
+ $editsectionSection = "T-$sectionIndex";
+ $editsectionContent = null;
} else {
- $editlinkArgs = array( $this->mTitle->getPrefixedText(), $sectionIndex, $headlineHint );
+ $editsectionPage = $this->mTitle->getPrefixedText();
+ $editsectionSection = $sectionIndex;
+ $editsectionContent = $headlineHint;
}
- // We use a bit of pesudo-xml for editsection markers. The language converter is run later on
- // Using a UNIQ style marker leads to the converter screwing up the tokens when it converts stuff
- // And trying to insert strip tags fails too. At this point all real inputted tags have already been escaped
- // so we don't have to worry about a user trying to input one of these markers directly.
- // We use a page and section attribute to stop the language converter from converting these important bits
- // of data, but put the headline hint inside a content block because the language converter is supposed to
+ // We use a bit of pesudo-xml for editsection markers. The
+ // language converter is run later on. Using a UNIQ style marker
+ // leads to the converter screwing up the tokens when it
+ // converts stuff. And trying to insert strip tags fails too. At
+ // this point all real inputted tags have already been escaped,
+ // so we don't have to worry about a user trying to input one of
+ // these markers directly. We use a page and section attribute
+ // to stop the language converter from converting these
+ // important bits of data, but put the headline hint inside a
+ // content block because the language converter is supposed to
// be able to convert that piece of data.
- $editlink = '<mw:editsection page="' . htmlspecialchars( $editlinkArgs[0] );
- $editlink .= '" section="' . htmlspecialchars( $editlinkArgs[1] ) . '"';
- if ( isset( $editlinkArgs[2] ) ) {
- $editlink .= '>' . $editlinkArgs[2] . '</mw:editsection>';
+ // Gets replaced with html in ParserOutput::getText
+ $editlink = '<mw:editsection page="' . htmlspecialchars( $editsectionPage );
+ $editlink .= '" section="' . htmlspecialchars( $editsectionSection ) . '"';
+ if ( $editsectionContent !== null ) {
+ $editlink .= '>' . $editsectionContent . '</mw:editsection>';
} else {
$editlink .= '/>';
}
@@ -4521,6 +4683,7 @@ class Parser {
$toc = Linker::tocList( $toc, $this->mOptions->getUserLangObj() );
$this->mOutput->setTOCHTML( $toc );
$toc = self::TOC_START . $toc . self::TOC_END;
+ $this->mOutput->addModules( 'mediawiki.toc' );
}
if ( $isMain ) {
@@ -4575,14 +4738,19 @@ class Parser {
* Transform wiki markup when saving a page by doing "\r\n" -> "\n"
* conversion, substitting signatures, {{subst:}} templates, etc.
*
- * @param string $text the text to transform
- * @param $title Title: the Title object for the current article
- * @param $user User: the User object describing the current user
- * @param $options ParserOptions: parsing options
- * @param $clearState Boolean: whether to clear the parser state first
- * @return String: the altered wiki markup
+ * @param string $text The text to transform
+ * @param Title $title The Title object for the current article
+ * @param User $user The User object describing the current user
+ * @param ParserOptions $options Parsing options
+ * @param bool $clearState Whether to clear the parser state first
+ * @return string The altered wiki markup
*/
- public function preSaveTransform( $text, Title $title, User $user, ParserOptions $options, $clearState = true ) {
+ public function preSaveTransform( $text, Title $title, User $user,
+ ParserOptions $options, $clearState = true
+ ) {
+ if ( $clearState ) {
+ $magicScopeVariable = $this->lock();
+ }
$this->startParse( $title, $options, self::OT_WIKI, $clearState );
$this->setUser( $user );
@@ -4602,14 +4770,13 @@ class Parser {
/**
* Pre-save transform helper function
- * @private
*
- * @param $text string
- * @param $user User
+ * @param string $text
+ * @param User $user
*
* @return string
*/
- function pstPass2( $text, $user ) {
+ private function pstPass2( $text, $user ) {
global $wgContLang;
# Note: This is the timestamp saved as hardcoded wikitext to
@@ -4652,10 +4819,14 @@ class Parser {
$tc = '[' . Title::legalChars() . ']';
$nc = '[ _0-9A-Za-z\x80-\xff-]'; # Namespaces can use non-ascii!
- $p1 = "/\[\[(:?$nc+:|:|)($tc+?)( ?\\($tc+\\))\\|]]/"; # [[ns:page (context)|]]
- $p4 = "/\[\[(:?$nc+:|:|)($tc+?)( ?($tc+))\\|]]/"; # [[ns:page(context)|]] (double-width brackets, added in r40257)
- $p3 = "/\[\[(:?$nc+:|:|)($tc+?)( ?\\($tc+\\)|)((?:, |,)$tc+|)\\|]]/"; # [[ns:page (context), context|]] (using either single or double-width comma)
- $p2 = "/\[\[\\|($tc+)]]/"; # [[|page]] (reverse pipe trick: add context from page title)
+ // [[ns:page (context)|]]
+ $p1 = "/\[\[(:?$nc+:|:|)($tc+?)( ?\\($tc+\\))\\|]]/";
+ // [[ns:page(context)|]] (double-width brackets, added in r40257)
+ $p4 = "/\[\[(:?$nc+:|:|)($tc+?)( ?($tc+))\\|]]/";
+ // [[ns:page (context), context|]] (using either single or double-width comma)
+ $p3 = "/\[\[(:?$nc+:|:|)($tc+?)( ?\\($tc+\\)|)((?:, |,)$tc+|)\\|]]/";
+ // [[|page]] (reverse pipe trick: add context from page title)
+ $p2 = "/\[\[\\|($tc+)]]/";
# try $p1 first, to turn "[[A, B (C)|]]" into "[[A, B (C)|A, B]]"
$text = preg_replace( $p1, '[[\\1\\2\\3|\\2]]', $text );
@@ -4687,13 +4858,13 @@ class Parser {
* Do not reuse this parser instance after calling getUserSig(),
* as it may have changed if it's the $wgParser.
*
- * @param $user User
- * @param string|bool $nickname nickname to use or false to use user's default nickname
- * @param $fancySig Boolean|null whether the nicknname is the complete signature
- * or null to use default value
+ * @param User $user
+ * @param string|bool $nickname Nickname to use or false to use user's default nickname
+ * @param bool|null $fancySig whether the nicknname is the complete signature
+ * or null to use default value
* @return string
*/
- function getUserSig( &$user, $nickname = false, $fancySig = null ) {
+ public function getUserSig( &$user, $nickname = false, $fancySig = null ) {
global $wgMaxSigChars;
$username = $user->getName();
@@ -4732,16 +4903,17 @@ class Parser {
$nickText = wfEscapeWikiText( $nickname );
$msgName = $user->isAnon() ? 'signature-anon' : 'signature';
- return wfMessage( $msgName, $userText, $nickText )->inContentLanguage()->title( $this->getTitle() )->text();
+ return wfMessage( $msgName, $userText, $nickText )->inContentLanguage()
+ ->title( $this->getTitle() )->text();
}
/**
* Check that the user's signature contains no bad XML
*
- * @param $text String
- * @return mixed An expanded string, or false if invalid.
+ * @param string $text
+ * @return string|bool An expanded string, or false if invalid.
*/
- function validateSig( $text ) {
+ public function validateSig( $text ) {
return Xml::isWellFormedXmlFragment( $text ) ? $text : false;
}
@@ -4751,13 +4923,14 @@ class Parser {
* 1) Strip ~~~, ~~~~ and ~~~~~ out of signatures @see cleanSigInSig
* 2) Substitute all transclusions
*
- * @param $text String
+ * @param string $text
* @param bool $parsing Whether we're cleaning (preferences save) or parsing
- * @return String: signature text
+ * @return string Signature text
*/
public function cleanSig( $text, $parsing = false ) {
if ( !$parsing ) {
global $wgTitle;
+ $magicScopeVariable = $this->lock();
$this->startParse( $wgTitle, new ParserOptions, self::OT_PREPROCESS, true );
}
@@ -4788,8 +4961,8 @@ class Parser {
/**
* Strip ~~~, ~~~~ and ~~~~~ out of signatures
*
- * @param $text String
- * @return String: signature text with /~{3,5}/ removed
+ * @param string $text
+ * @return string Signature text with /~{3,5}/ removed
*/
public static function cleanSigInSig( $text ) {
$text = preg_replace( '/~{3,5}/', '', $text );
@@ -4800,22 +4973,26 @@ class Parser {
* Set up some variables which are usually set up in parse()
* so that an external function can call some class members with confidence
*
- * @param $title Title|null
- * @param $options ParserOptions
- * @param $outputType
- * @param $clearState bool
+ * @param Title|null $title
+ * @param ParserOptions $options
+ * @param int $outputType
+ * @param bool $clearState
*/
- public function startExternalParse( Title $title = null, ParserOptions $options, $outputType, $clearState = true ) {
+ public function startExternalParse( Title $title = null, ParserOptions $options,
+ $outputType, $clearState = true
+ ) {
$this->startParse( $title, $options, $outputType, $clearState );
}
/**
- * @param $title Title|null
- * @param $options ParserOptions
- * @param $outputType
- * @param $clearState bool
+ * @param Title|null $title
+ * @param ParserOptions $options
+ * @param int $outputType
+ * @param bool $clearState
*/
- private function startParse( Title $title = null, ParserOptions $options, $outputType, $clearState = true ) {
+ private function startParse( Title $title = null, ParserOptions $options,
+ $outputType, $clearState = true
+ ) {
$this->setTitle( $title );
$this->mOptions = $options;
$this->setOutputType( $outputType );
@@ -4827,10 +5004,10 @@ class Parser {
/**
* Wrapper for preprocess()
*
- * @param string $text the text to preprocess
- * @param $options ParserOptions: options
- * @param $title Title object or null to use $wgTitle
- * @return String
+ * @param string $text The text to preprocess
+ * @param ParserOptions $options Options
+ * @param Title|null $title Title object or null to use $wgTitle
+ * @return string
*/
public function transformMsg( $text, $options, $title = null ) {
static $executing = false;
@@ -4873,10 +5050,10 @@ class Parser {
* this interface, as it is not documented and injudicious use could smash
* private variables.**
*
- * @param $tag Mixed: the tag to use, e.g. 'hook' for "<hook>"
- * @param $callback Mixed: the callback function (and object) to use for the tag
+ * @param string $tag The tag to use, e.g. 'hook' for "<hook>"
+ * @param callable $callback The callback function (and object) to use for the tag
* @throws MWException
- * @return Mixed|null The old value of the mTagHooks array associated with the hook
+ * @return callable|null The old value of the mTagHooks array associated with the hook
*/
public function setHook( $tag, $callback ) {
$tag = strtolower( $tag );
@@ -4904,12 +5081,12 @@ class Parser {
* @since 1.10
* @todo better document or deprecate this
*
- * @param $tag Mixed: the tag to use, e.g. 'hook' for "<hook>"
- * @param $callback Mixed: the callback function (and object) to use for the tag
+ * @param string $tag The tag to use, e.g. 'hook' for "<hook>"
+ * @param callable $callback The callback function (and object) to use for the tag
* @throws MWException
- * @return Mixed|null The old value of the mTagHooks array associated with the hook
+ * @return callable|null The old value of the mTagHooks array associated with the hook
*/
- function setTransparentTagHook( $tag, $callback ) {
+ public function setTransparentTagHook( $tag, $callback ) {
$tag = strtolower( $tag );
if ( preg_match( '/[<>\r\n]/', $tag, $m ) ) {
throw new MWException( "Invalid character {$m[0]} in setTransparentHook('$tag', ...) call" );
@@ -4923,7 +5100,7 @@ class Parser {
/**
* Remove all tag hooks
*/
- function clearTagHooks() {
+ public function clearTagHooks() {
$this->mTagHooks = array();
$this->mFunctionTagHooks = array();
$this->mStripList = $this->mDefaultStripList;
@@ -4946,8 +5123,8 @@ class Parser {
* isHTML The returned text is HTML, armour it against wikitext transformation
*
* @param string $id The magic word ID
- * @param $callback Mixed: the callback function (and object) to use
- * @param $flags Integer: a combination of the following flags:
+ * @param callable $callback The callback function (and object) to use
+ * @param int $flags A combination of the following flags:
* SFH_NO_HASH No leading hash, i.e. {{plural:...}} instead of {{#if:...}}
*
* SFH_OBJECT_ARGS Pass the template arguments as PPNode objects instead of text. This
@@ -4970,7 +5147,7 @@ class Parser {
* about the methods available in PPFrame and PPNode.
*
* @throws MWException
- * @return string|callback The old callback function for this name, if any
+ * @return string|callable The old callback function for this name, if any
*/
public function setFunctionHook( $id, $callback, $flags = 0 ) {
global $wgContLang;
@@ -5008,9 +5185,9 @@ class Parser {
/**
* Get all registered function hook identifiers
*
- * @return Array
+ * @return array
*/
- function getFunctionHooks() {
+ public function getFunctionHooks() {
return array_keys( $this->mFunctionHooks );
}
@@ -5018,13 +5195,13 @@ class Parser {
* Create a tag function, e.g. "<test>some stuff</test>".
* Unlike tag hooks, tag functions are parsed at preprocessor level.
* Unlike parser functions, their content is not preprocessed.
- * @param $tag
- * @param $callback
- * @param $flags
+ * @param string $tag
+ * @param callable $callback
+ * @param int $flags
* @throws MWException
* @return null
*/
- function setFunctionTagHook( $tag, $callback, $flags ) {
+ public function setFunctionTagHook( $tag, $callback, $flags ) {
$tag = strtolower( $tag );
if ( preg_match( '/[<>\r\n]/', $tag, $m ) ) {
throw new MWException( "Invalid character {$m[0]} in setFunctionTagHook('$tag', ...) call" );
@@ -5045,12 +5222,12 @@ class Parser {
* Replace "<!--LINK-->" link placeholders with actual links, in the buffer
* Placeholders created in Skin::makeLinkObj()
*
- * @param $text string
- * @param $options int
+ * @param string $text
+ * @param int $options
*
- * @return array of link CSS classes, indexed by PDBK.
+ * @return array Array of link CSS classes, indexed by PDBK.
*/
- function replaceLinkHolders( &$text, $options = 0 ) {
+ public function replaceLinkHolders( &$text, $options = 0 ) {
return $this->mLinkHolders->replace( $text );
}
@@ -5058,10 +5235,10 @@ class Parser {
* Replace "<!--LINK-->" link placeholders with plain text of links
* (not HTML-formatted).
*
- * @param $text String
- * @return String
+ * @param string $text
+ * @return string
*/
- function replaceLinkHoldersText( $text ) {
+ public function replaceLinkHoldersText( $text ) {
return $this->mLinkHolders->replaceText( $text );
}
@@ -5078,7 +5255,7 @@ class Parser {
* @param array $params
* @return string HTML
*/
- function renderImageGallery( $text, $params ) {
+ public function renderImageGallery( $text, $params ) {
wfProfileIn( __METHOD__ );
$mode = false;
@@ -5203,7 +5380,7 @@ class Parser {
} else {
$localLinkTitle = Title::newFromText( $linkValue );
if ( $localLinkTitle !== null ) {
- $link = $localLinkTitle->getLocalURL();
+ $link = $localLinkTitle->getLinkURL();
}
}
break;
@@ -5213,7 +5390,7 @@ class Parser {
$handlerOptions[$paramName] = $match;
} else {
// Guess not. Append it to the caption.
- wfDebug( "$parameterMatch failed parameter validation" );
+ wfDebug( "$parameterMatch failed parameter validation\n" );
$label .= '|' . $parameterMatch;
}
}
@@ -5230,15 +5407,16 @@ class Parser {
$ig->add( $title, $label, $alt, $link, $handlerOptions );
}
$html = $ig->toHTML();
+ wfRunHooks( 'AfterParserFetchFileAndTitle', array( $this, $ig, &$html ) );
wfProfileOut( __METHOD__ );
return $html;
}
/**
- * @param $handler
+ * @param string $handler
* @return array
*/
- function getImageParams( $handler ) {
+ public function getImageParams( $handler ) {
if ( $handler ) {
$handlerClass = get_class( $handler );
} else {
@@ -5281,12 +5459,12 @@ class Parser {
/**
* Parse image options text and use it to make an image
*
- * @param $title Title
- * @param $options String
- * @param $holders LinkHolderArray|bool
+ * @param Title $title
+ * @param string $options
+ * @param LinkHolderArray|bool $holders
* @return string HTML
*/
- function makeImage( $title, $options, $holders = false ) {
+ public function makeImage( $title, $options, $holders = false ) {
# Check if the options text is of the form "options|alt text"
# Options are:
# * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang
@@ -5336,6 +5514,7 @@ class Parser {
$caption = '';
$params = array( 'frame' => array(), 'handler' => array(),
'horizAlign' => array(), 'vertAlign' => array() );
+ $seenformat = false;
foreach ( $parts as $part ) {
$part = trim( $part );
list( $magicName, $value ) = $mwArray->matchVariableStartToEnd( $part );
@@ -5384,7 +5563,7 @@ class Parser {
$paramName = 'no-link';
$value = true;
$validated = true;
- } elseif ( preg_match( "/^(?i)$prots/", $value ) ) {
+ } elseif ( preg_match( "/^((?i)$prots)/", $value ) ) {
if ( preg_match( "/^((?i)$prots)$chars+$/u", $value, $m ) ) {
$paramName = 'link-url';
$this->mOutput->addExternalLink( $value );
@@ -5403,6 +5582,13 @@ class Parser {
}
}
break;
+ case 'frameless':
+ case 'framed':
+ case 'thumbnail':
+ // use first appearing option, discard others.
+ $validated = ! $seenformat;
+ $seenformat = true;
+ break;
default:
# Most other things appear to be empty or numeric...
$validated = ( $value === false || is_numeric( trim( $value ) ) );
@@ -5430,10 +5616,10 @@ class Parser {
$params['frame']['caption'] = $caption;
# Will the image be presented in a frame, with the caption below?
- $imageIsFramed = isset( $params['frame']['frame'] ) ||
- isset( $params['frame']['framed'] ) ||
- isset( $params['frame']['thumbnail'] ) ||
- isset( $params['frame']['manualthumb'] );
+ $imageIsFramed = isset( $params['frame']['frame'] )
+ || isset( $params['frame']['framed'] )
+ || isset( $params['frame']['thumbnail'] )
+ || isset( $params['frame']['manualthumb'] );
# In the old days, [[Image:Foo|text...]] would set alt text. Later it
# came to also set the caption, ordinary text after the image -- which
@@ -5490,9 +5676,9 @@ class Parser {
}
/**
- * @param $caption
- * @param $holders LinkHolderArray
- * @return mixed|String
+ * @param string $caption
+ * @param LinkHolderArray|bool $holders
+ * @return mixed|string
*/
protected function stripAltText( $caption, $holders ) {
# Strip bad stuff out of the title (tooltip). We can't just use
@@ -5517,7 +5703,7 @@ class Parser {
* Set a flag in the output object indicating that the content is dynamic and
* shouldn't be cached.
*/
- function disableCache() {
+ public function disableCache() {
wfDebug( "Parser output marked as uncacheable.\n" );
if ( !$this->mOutput ) {
throw new MWException( __METHOD__ .
@@ -5531,11 +5717,11 @@ class Parser {
* Callback from the Sanitizer for expanding items found in HTML attribute
* values, so they can be safely tested and escaped.
*
- * @param $text String
- * @param $frame PPFrame
- * @return String
+ * @param string $text
+ * @param bool|PPFrame $frame
+ * @return string
*/
- function attributeStripCallback( &$text, $frame = false ) {
+ public function attributeStripCallback( &$text, $frame = false ) {
$text = $this->replaceVariables( $text, $frame );
$text = $this->mStripState->unstripBoth( $text );
return $text;
@@ -5546,8 +5732,12 @@ class Parser {
*
* @return array
*/
- function getTags() {
- return array_merge( array_keys( $this->mTransparentTagHooks ), array_keys( $this->mTagHooks ), array_keys( $this->mFunctionTagHooks ) );
+ public function getTags() {
+ return array_merge(
+ array_keys( $this->mTransparentTagHooks ),
+ array_keys( $this->mTagHooks ),
+ array_keys( $this->mFunctionTagHooks )
+ );
}
/**
@@ -5556,11 +5746,11 @@ class Parser {
* Transparent tag hooks are like regular XML-style tag hooks, except they
* operate late in the transformation sequence, on HTML instead of wikitext.
*
- * @param $text string
+ * @param string $text
*
* @return string
*/
- function replaceTransparentTags( $text ) {
+ public function replaceTransparentTags( $text ) {
$matches = array();
$elements = array_keys( $this->mTransparentTagHooks );
$text = self::extractTagsAndParams( $elements, $text, $matches, $this->mUniqPrefix );
@@ -5570,7 +5760,10 @@ class Parser {
list( $element, $content, $params, $tag ) = $data;
$tagName = strtolower( $element );
if ( isset( $this->mTransparentTagHooks[$tagName] ) ) {
- $output = call_user_func_array( $this->mTransparentTagHooks[$tagName], array( $content, $params, $this ) );
+ $output = call_user_func_array(
+ $this->mTransparentTagHooks[$tagName],
+ array( $content, $params, $this )
+ );
} else {
$output = $tag;
}
@@ -5586,7 +5779,7 @@ class Parser {
* External callers should use the getSection and replaceSection methods.
*
* @param string $text Page wikitext
- * @param string $section a section identifier string of the form:
+ * @param string|number $sectionId A section identifier string of the form:
* "<flag1> - <flag2> - ... - <section number>"
*
* Currently the only recognised flag is "T", which means the target section number
@@ -5603,20 +5796,22 @@ class Parser {
* string. If $text is the empty string and section 0 is replaced, $newText is
* returned.
*
- * @param string $mode one of "get" or "replace"
- * @param string $newText replacement text for section data.
- * @return String: for "get", the extracted section text.
- * for "replace", the whole page with the section replaced.
+ * @param string $mode One of "get" or "replace"
+ * @param string $newText Replacement text for section data.
+ * @return string For "get", the extracted section text.
+ * for "replace", the whole page with the section replaced.
*/
- private function extractSections( $text, $section, $mode, $newText = '' ) {
+ private function extractSections( $text, $sectionId, $mode, $newText = '' ) {
global $wgTitle; # not generally used but removes an ugly failure mode
+
+ $magicScopeVariable = $this->lock();
$this->startParse( $wgTitle, new ParserOptions, self::OT_PLAIN, true );
$outText = '';
$frame = $this->getPreprocessor()->newFrame();
# Process section extraction flags
$flags = 0;
- $sectionParts = explode( '-', $section );
+ $sectionParts = explode( '-', $sectionId );
$sectionIndex = array_pop( $sectionParts );
foreach ( $sectionParts as $part ) {
if ( $part === 'T' ) {
@@ -5724,13 +5919,15 @@ class Parser {
*
* If a section contains subsections, these are also returned.
*
- * @param string $text text to look in
- * @param string $section section identifier
- * @param string $deftext default to return if section is not found
- * @return string text of the requested section
+ * @param string $text Text to look in
+ * @param string|number $sectionId Section identifier as a number or string
+ * (e.g. 0, 1 or 'T-1').
+ * @param string $defaultText Default to return if section is not found
+ *
+ * @return string Text of the requested section
*/
- public function getSection( $text, $section, $deftext = '' ) {
- return $this->extractSections( $text, $section, "get", $deftext );
+ public function getSection( $text, $sectionId, $defaultText = '' ) {
+ return $this->extractSections( $text, $sectionId, 'get', $defaultText );
}
/**
@@ -5738,30 +5935,33 @@ class Parser {
* specified by $section has been replaced with $text. If the target
* section does not exist, $oldtext is returned unchanged.
*
- * @param string $oldtext former text of the article
- * @param int $section section identifier
- * @param string $text replacing text
- * @return String: modified text
+ * @param string $oldText Former text of the article
+ * @param string|number $sectionId Section identifier as a number or string
+ * (e.g. 0, 1 or 'T-1').
+ * @param string $newText Replacing text
+ *
+ * @return string Modified text
*/
- public function replaceSection( $oldtext, $section, $text ) {
- return $this->extractSections( $oldtext, $section, "replace", $text );
+ public function replaceSection( $oldText, $sectionId, $newText ) {
+ return $this->extractSections( $oldText, $sectionId, 'replace', $newText );
}
/**
* Get the ID of the revision we are parsing
*
- * @return Mixed: integer or null
+ * @return int|null
*/
- function getRevisionId() {
+ public function getRevisionId() {
return $this->mRevisionId;
}
/**
* Get the revision object for $this->mRevisionId
*
- * @return Revision|null either a Revision object or null
+ * @return Revision|null Either a Revision object or null
+ * @since 1.23 (public since 1.23)
*/
- protected function getRevisionObject() {
+ public function getRevisionObject() {
if ( !is_null( $this->mRevisionObject ) ) {
return $this->mRevisionObject;
}
@@ -5776,8 +5976,9 @@ class Parser {
/**
* Get the timestamp associated with the current revision, adjusted for
* the default server-local timestamp
+ * @return string
*/
- function getRevisionTimestamp() {
+ public function getRevisionTimestamp() {
if ( is_null( $this->mRevisionTimestamp ) ) {
wfProfileIn( __METHOD__ );
@@ -5802,9 +6003,9 @@ class Parser {
/**
* Get the name of the user that edited the last revision
*
- * @return String: user name
+ * @return string User name
*/
- function getRevisionUser() {
+ public function getRevisionUser() {
if ( is_null( $this->mRevisionUser ) ) {
$revObject = $this->getRevisionObject();
@@ -5822,9 +6023,9 @@ class Parser {
/**
* Get the size of the revision
*
- * @return int|null revision size
+ * @return int|null Revision size
*/
- function getRevisionSize() {
+ public function getRevisionSize() {
if ( is_null( $this->mRevisionSize ) ) {
$revObject = $this->getRevisionObject();
@@ -5872,7 +6073,7 @@ class Parser {
* Accessor for $mDefaultSort
* Unlike getDefaultSort(), will return false if none is set
*
- * @return string or false
+ * @return string|bool
*/
public function getCustomDefaultSort() {
return $this->mDefaultSort;
@@ -5883,7 +6084,7 @@ class Parser {
* presumably extracted from a heading, for example "Header" from
* "== Header ==".
*
- * @param $text string
+ * @param string $text
*
* @return string
*/
@@ -5919,7 +6120,7 @@ class Parser {
* to create valid section anchors by mimicing the output of the
* parser when headings are parsed.
*
- * @param string $text text string to be stripped of wikitext
+ * @param string $text Text string to be stripped of wikitext
* for use in a Section anchor
* @return string Filtered text string
*/
@@ -5930,7 +6131,7 @@ class Parser {
# Strip external link markup
# @todo FIXME: Not tolerant to blank link text
- # I.E. [http://www.mediawiki.org] will render as [1] or something depending
+ # I.E. [https://www.mediawiki.org] will render as [1] or something depending
# on how many empty links there are on the page - need to figure that out.
$text = preg_replace( '/\[(?i:' . $this->mUrlProtocols . ')([^ ]+?) ([^[]+)\]/', '$2', $text );
@@ -5945,14 +6146,15 @@ class Parser {
/**
* strip/replaceVariables/unstrip for preprocessor regression testing
*
- * @param $text string
- * @param $title Title
- * @param $options ParserOptions
- * @param $outputType int
+ * @param string $text
+ * @param Title $title
+ * @param ParserOptions $options
+ * @param int $outputType
*
* @return string
*/
- function testSrvus( $text, Title $title, ParserOptions $options, $outputType = self::OT_HTML ) {
+ public function testSrvus( $text, Title $title, ParserOptions $options, $outputType = self::OT_HTML ) {
+ $magicScopeVariable = $this->lock();
$this->startParse( $title, $options, $outputType, true );
$text = $this->replaceVariables( $text );
@@ -5962,22 +6164,22 @@ class Parser {
}
/**
- * @param $text string
- * @param $title Title
- * @param $options ParserOptions
+ * @param string $text
+ * @param Title $title
+ * @param ParserOptions $options
* @return string
*/
- function testPst( $text, Title $title, ParserOptions $options ) {
+ public function testPst( $text, Title $title, ParserOptions $options ) {
return $this->preSaveTransform( $text, $title, $options->getUser(), $options );
}
/**
- * @param $text
- * @param $title Title
- * @param $options ParserOptions
+ * @param string $text
+ * @param Title $title
+ * @param ParserOptions $options
* @return string
*/
- function testPreprocess( $text, Title $title, ParserOptions $options ) {
+ public function testPreprocess( $text, Title $title, ParserOptions $options ) {
return $this->testSrvus( $text, $title, $options, self::OT_PREPROCESS );
}
@@ -5992,12 +6194,12 @@ class Parser {
* two strings will be replaced with the value returned by the callback in
* each case.
*
- * @param $s string
- * @param $callback
+ * @param string $s
+ * @param callable $callback
*
* @return string
*/
- function markerSkipCallback( $s, $callback ) {
+ public function markerSkipCallback( $s, $callback ) {
$i = 0;
$out = '';
while ( $i < strlen( $s ) ) {
@@ -6024,10 +6226,10 @@ class Parser {
/**
* Remove any strip markers found in the given text.
*
- * @param $text Input string
+ * @param string $text Input string
* @return string
*/
- function killMarkers( $text ) {
+ public function killMarkers( $text ) {
return $this->mStripState->killMarkers( $text );
}
@@ -6043,11 +6245,11 @@ class Parser {
* unserializeHalfParsedText(). The text can then be safely incorporated into
* the return value of a parser hook.
*
- * @param $text string
+ * @param string $text
*
* @return array
*/
- function serializeHalfParsedText( $text ) {
+ public function serializeHalfParsedText( $text ) {
wfProfileIn( __METHOD__ );
$data = array(
'text' => $text,
@@ -6072,9 +6274,9 @@ class Parser {
*
* @param array $data Serialized data
* @throws MWException
- * @return String
+ * @return string
*/
- function unserializeHalfParsedText( $data ) {
+ public function unserializeHalfParsedText( $data ) {
if ( !isset( $data['version'] ) || $data['version'] != self::HALF_PARSED_VERSION ) {
throw new MWException( __METHOD__ . ': invalid version' );
}
@@ -6095,18 +6297,18 @@ class Parser {
* serializeHalfParsedText(), is compatible with the current version of the
* parser.
*
- * @param $data Array
+ * @param array $data
*
* @return bool
*/
- function isValidHalfParsedText( $data ) {
+ public function isValidHalfParsedText( $data ) {
return isset( $data['version'] ) && $data['version'] == self::HALF_PARSED_VERSION;
}
/**
* Parsed a width param of imagelink like 300px or 200x300px
*
- * @param $value String
+ * @param string $value
*
* @return array
* @since 1.20
@@ -6130,4 +6332,68 @@ class Parser {
}
return $parsedWidthParam;
}
+
+ /**
+ * Lock the current instance of the parser.
+ *
+ * This is meant to stop someone from calling the parser
+ * recursively and messing up all the strip state.
+ *
+ * @throws MWException If parser is in a parse
+ * @return ScopedCallback The lock will be released once the return value goes out of scope.
+ */
+ protected function lock() {
+ if ( $this->mInParse ) {
+ throw new MWException( "Parser state cleared while parsing. "
+ . "Did you call Parser::parse recursively?" );
+ }
+ $this->mInParse = true;
+
+ $that = $this;
+ $recursiveCheck = new ScopedCallback( function() use ( $that ) {
+ $that->mInParse = false;
+ } );
+
+ return $recursiveCheck;
+ }
+
+ /**
+ * Strip outer <p></p> tag from the HTML source of a single paragraph.
+ *
+ * Returns original HTML if the <p/> tag has any attributes, if there's no wrapping <p/> tag,
+ * or if there is more than one <p/> tag in the input HTML.
+ *
+ * @param string $html
+ * @return string
+ * @since 1.24
+ */
+ public static function stripOuterParagraph( $html ) {
+ $m = array();
+ if ( preg_match( '/^<p>(.*)\n?<\/p>\n?$/sU', $html, $m ) ) {
+ if ( strpos( $m[1], '</p>' ) === false ) {
+ $html = $m[1];
+ }
+ }
+
+ return $html;
+ }
+
+ /**
+ * Return this parser if it is not doing anything, otherwise
+ * get a fresh parser. You can use this method by doing
+ * $myParser = $wgParser->getFreshParser(), or more simply
+ * $wgParser->getFreshParser()->parse( ... );
+ * if you're unsure if $wgParser is safe to use.
+ *
+ * @since 1.24
+ * @return Parser A parser object that is not parsing anything
+ */
+ public function getFreshParser() {
+ global $wgParserConf;
+ if ( $this->mInParse ) {
+ return new $wgParserConf['class']( $wgParserConf );
+ } else {
+ return $this;
+ }
+ }
}
diff --git a/includes/parser/ParserCache.php b/includes/parser/ParserCache.php
index 7053f134..79523003 100644
--- a/includes/parser/ParserCache.php
+++ b/includes/parser/ParserCache.php
@@ -26,9 +26,8 @@
* @todo document
*/
class ParserCache {
+ /** @var MWMemcached */
private $mMemc;
- const try116cache = false; /* Only useful $wgParserCacheExpireTime after updating to 1.17 */
-
/**
* Get an instance of this object
*
@@ -47,7 +46,7 @@ class ParserCache {
* Setup a cache pathway with a given back-end storage mechanism.
* May be a memcached client or a BagOStuff derivative.
*
- * @param $memCached Object
+ * @param MWMemcached $memCached
* @throws MWException
*/
protected function __construct( $memCached ) {
@@ -58,8 +57,8 @@ class ParserCache {
}
/**
- * @param $article Article
- * @param $hash string
+ * @param Article $article
+ * @param string $hash
* @return mixed|string
*/
protected function getParserOutputKey( $article, $hash ) {
@@ -74,7 +73,7 @@ class ParserCache {
}
/**
- * @param $article Article
+ * @param Article $article
* @return mixed|string
*/
protected function getOptionsKey( $article ) {
@@ -92,11 +91,11 @@ class ParserCache {
* English preferences. That's why we take into account *all* user
* options. (r70809 CR)
*
- * @param $article Article
- * @param $popts ParserOptions
+ * @param Article $article
+ * @param ParserOptions $popts
* @return string
*/
- function getETag( $article, $popts ) {
+ public function getETag( $article, $popts ) {
return 'W/"' . $this->getParserOutputKey( $article,
$popts->optionsHash( ParserOptions::legacyOptions(), $article->getTitle() ) ) .
"--" . $article->getTouched() . '"';
@@ -104,8 +103,8 @@ class ParserCache {
/**
* Retrieve the ParserOutput from ParserCache, even if it's outdated.
- * @param $article Article
- * @param $popts ParserOptions
+ * @param Article $article
+ * @param ParserOptions $popts
* @return ParserOutput|bool False on failure
*/
public function getDirty( $article, $popts ) {
@@ -114,15 +113,22 @@ class ParserCache {
}
/**
- * Used to provide a unique id for the PoolCounter.
+ * Generates a key for caching the given article considering
+ * the given parser options.
+ *
+ * @note Which parser options influence the cache key
+ * is controlled via ParserOutput::recordOption() or
+ * ParserOptions::addExtraKey().
+ *
+ * @note Used by Article to provide a unique id for the PoolCounter.
* It would be preferable to have this code in get()
* instead of having Article looking in our internals.
*
* @todo Document parameter $useOutdated
*
- * @param $article Article
- * @param $popts ParserOptions
- * @param $useOutdated Boolean (default true)
+ * @param Article $article
+ * @param ParserOptions $popts
+ * @param bool $useOutdated (default true)
* @return bool|mixed|string
*/
public function getKey( $article, $popts, $useOutdated = true ) {
@@ -139,29 +145,40 @@ class ParserCache {
if ( !$useOutdated && $optionsKey->expired( $article->getTouched() ) ) {
wfIncrStats( "pcache_miss_expired" );
$cacheTime = $optionsKey->getCacheTime();
- wfDebug( "Parser options key expired, touched " . $article->getTouched() . ", epoch $wgCacheEpoch, cached $cacheTime\n" );
+ wfDebug( "Parser options key expired, touched " . $article->getTouched()
+ . ", epoch $wgCacheEpoch, cached $cacheTime\n" );
+ return false;
+ } elseif ( $optionsKey->isDifferentRevision( $article->getLatest() ) ) {
+ wfIncrStats( "pcache_miss_revid" );
+ $revId = $article->getLatest();
+ $cachedRevId = $optionsKey->getCacheRevisionId();
+ wfDebug( "ParserOutput key is for an old revision, latest $revId, cached $cachedRevId\n" );
return false;
}
+ // $optionsKey->mUsedOptions is set by save() by calling ParserOutput::getUsedOptions()
$usedOptions = $optionsKey->mUsedOptions;
wfDebug( "Parser cache options found.\n" );
} else {
- if ( !$useOutdated && !self::try116cache ) {
+ if ( !$useOutdated ) {
return false;
}
$usedOptions = ParserOptions::legacyOptions();
}
- return $this->getParserOutputKey( $article, $popts->optionsHash( $usedOptions, $article->getTitle() ) );
+ return $this->getParserOutputKey(
+ $article,
+ $popts->optionsHash( $usedOptions, $article->getTitle() )
+ );
}
/**
* Retrieve the ParserOutput from ParserCache.
* false if not found or outdated.
*
- * @param $article Article
- * @param $popts ParserOptions
- * @param $useOutdated Boolean (default false)
+ * @param Article $article
+ * @param ParserOptions $popts
+ * @param bool $useOutdated (default false)
*
* @return ParserOutput|bool False on failure
*/
@@ -186,12 +203,6 @@ class ParserCache {
}
$value = $this->mMemc->get( $parserOutputKey );
- if ( self::try116cache && !$value && strpos( $value, '*' ) !== -1 ) {
- wfDebug( "New format parser cache miss.\n" );
- $parserOutputKey = $this->getParserOutputKey( $article,
- $popts->optionsHash( ParserOptions::legacyOptions(), $article->getTitle() ) );
- $value = $this->mMemc->get( $parserOutputKey );
- }
if ( !$value ) {
wfDebug( "ParserOutput cache miss.\n" );
wfIncrStats( "pcache_miss_absent" );
@@ -209,7 +220,14 @@ class ParserCache {
if ( !$useOutdated && $value->expired( $touched ) ) {
wfIncrStats( "pcache_miss_expired" );
$cacheTime = $value->getCacheTime();
- wfDebug( "ParserOutput key expired, touched $touched, epoch $wgCacheEpoch, cached $cacheTime\n" );
+ wfDebug( "ParserOutput key expired, touched $touched, "
+ . "epoch $wgCacheEpoch, cached $cacheTime\n" );
+ $value = false;
+ } elseif ( $value->isDifferentRevision( $article->getLatest() ) ) {
+ wfIncrStats( "pcache_miss_revid" );
+ $revId = $article->getLatest();
+ $cachedRevId = $value->getCacheRevisionId();
+ wfDebug( "ParserOutput key is for an old revision, latest $revId, cached $cachedRevId\n" );
$value = false;
} else {
wfIncrStats( "pcache_hit" );
@@ -220,15 +238,20 @@ class ParserCache {
}
/**
- * @param $parserOutput ParserOutput
- * @param $article Article
- * @param $popts ParserOptions
- * @param $cacheTime Time when the cache was generated
+ * @param ParserOutput $parserOutput
+ * @param WikiPage $page
+ * @param ParserOptions $popts
+ * @param string $cacheTime Time when the cache was generated
+ * @param int $revId Revision ID that was parsed
*/
- public function save( $parserOutput, $article, $popts, $cacheTime = null ) {
+ public function save( $parserOutput, $page, $popts, $cacheTime = null, $revId = null ) {
$expire = $parserOutput->getCacheExpiry();
if ( $expire > 0 ) {
$cacheTime = $cacheTime ?: wfTimestampNow();
+ if ( !$revId ) {
+ $revision = $page->getRevision();
+ $revId = $revision ? $revision->getId() : null;
+ }
$optionsKey = new CacheTime;
$optionsKey->mUsedOptions = $parserOutput->getUsedOptions();
@@ -236,23 +259,30 @@ class ParserCache {
$optionsKey->setCacheTime( $cacheTime );
$parserOutput->setCacheTime( $cacheTime );
+ $optionsKey->setCacheRevisionId( $revId );
+ $parserOutput->setCacheRevisionId( $revId );
$optionsKey->setContainsOldMagic( $parserOutput->containsOldMagic() );
- $parserOutputKey = $this->getParserOutputKey( $article,
- $popts->optionsHash( $optionsKey->mUsedOptions, $article->getTitle() ) );
+ $parserOutputKey = $this->getParserOutputKey( $page,
+ $popts->optionsHash( $optionsKey->mUsedOptions, $page->getTitle() ) );
// Save the timestamp so that we don't have to load the revision row on view
- $parserOutput->setTimestamp( $article->getTimestamp() );
+ $parserOutput->setTimestamp( $page->getTimestamp() );
+
+ $msg = "Saved in parser cache with key $parserOutputKey" .
+ " and timestamp $cacheTime" .
+ " and revision id $revId" .
+ "\n";
- $parserOutput->mText .= "\n<!-- Saved in parser cache with key $parserOutputKey and timestamp $cacheTime\n -->\n";
- wfDebug( "Saved in parser cache with key $parserOutputKey and timestamp $cacheTime\n" );
+ $parserOutput->mText .= "\n<!-- $msg -->\n";
+ wfDebug( $msg );
// Save the parser output
$this->mMemc->set( $parserOutputKey, $parserOutput, $expire );
// ...and its pointer
- $this->mMemc->set( $this->getOptionsKey( $article ), $optionsKey, $expire );
+ $this->mMemc->set( $this->getOptionsKey( $page ), $optionsKey, $expire );
} else {
wfDebug( "Parser output was marked as uncacheable and has not been saved.\n" );
}
diff --git a/includes/parser/Parser_DiffTest.php b/includes/parser/ParserDiffTest.php
index aeae234a..174c1d61 100644
--- a/includes/parser/Parser_DiffTest.php
+++ b/includes/parser/ParserDiffTest.php
@@ -24,21 +24,21 @@
/**
* @ingroup Parser
*/
-class Parser_DiffTest
+class ParserDiffTest
{
- var $parsers, $conf;
- var $shortOutput = false;
+ public $parsers;
+ public $conf;
+ public $shortOutput = false;
+ public $dtUniqPrefix;
- var $dtUniqPrefix;
-
- function __construct( $conf ) {
+ public function __construct( $conf ) {
if ( !isset( $conf['parsers'] ) ) {
throw new MWException( __METHOD__ . ': no parsers specified' );
}
$this->conf = $conf;
}
- function init() {
+ public function init() {
if ( !is_null( $this->parsers ) ) {
return;
}
@@ -64,7 +64,7 @@ class Parser_DiffTest
}
}
- function __call( $name, $args ) {
+ public function __call( $name, $args ) {
$this->init();
$results = array();
$mismatch = false;
@@ -98,7 +98,7 @@ class Parser_DiffTest
} else {
$diff = '[too many parsers]';
}
- $msg = "Parser_DiffTest: results mismatch on call to $name\n";
+ $msg = "ParserDiffTest: results mismatch on call to $name\n";
if ( !$this->shortOutput ) {
$msg .= 'Arguments: ' . $this->formatArray( $args ) . "\n";
}
@@ -109,7 +109,7 @@ class Parser_DiffTest
return $lastResult;
}
- function formatArray( $array ) {
+ public function formatArray( $array ) {
if ( $this->shortOutput ) {
foreach ( $array as $key => $value ) {
if ( $value instanceof ParserOutput ) {
@@ -120,7 +120,7 @@ class Parser_DiffTest
return var_export( $array, true );
}
- function setFunctionHook( $id, $callback, $flags = 0 ) {
+ public function setFunctionHook( $id, $callback, $flags = 0 ) {
$this->init();
foreach ( $this->parsers as $parser ) {
$parser->setFunctionHook( $id, $callback, $flags );
@@ -128,10 +128,10 @@ class Parser_DiffTest
}
/**
- * @param $parser Parser
+ * @param Parser $parser
* @return bool
*/
- function onClearState( &$parser ) {
+ public function onClearState( &$parser ) {
// hack marker prefixes to get identical output
if ( !isset( $this->dtUniqPrefix ) ) {
$this->dtUniqPrefix = $parser->uniqPrefix();
diff --git a/includes/parser/ParserOptions.php b/includes/parser/ParserOptions.php
index e12f32d8..7e4059b8 100644
--- a/includes/parser/ParserOptions.php
+++ b/includes/parser/ParserOptions.php
@@ -22,9 +22,10 @@
*/
/**
- * \brief Set options of the Parser
+ * @brief Set options of the Parser
*
- * All member variables are supposed to be private in theory, although in practise this is not the case.
+ * All member variables are supposed to be private in theory, although in
+ * practise this is not the case.
*
* @ingroup Parser
*/
@@ -33,108 +34,108 @@ class ParserOptions {
/**
* Interlanguage links are removed and returned in an array
*/
- var $mInterwikiMagic;
+ public $mInterwikiMagic;
/**
* Allow external images inline?
*/
- var $mAllowExternalImages;
+ public $mAllowExternalImages;
/**
* If not, any exception?
*/
- var $mAllowExternalImagesFrom;
+ public $mAllowExternalImagesFrom;
/**
* If not or it doesn't match, should we check an on-wiki whitelist?
*/
- var $mEnableImageWhitelist;
+ public $mEnableImageWhitelist;
/**
* Date format index
*/
- var $mDateFormat = null;
+ public $mDateFormat = null;
/**
* Create "edit section" links?
*/
- var $mEditSection = true;
+ public $mEditSection = true;
/**
* Allow inclusion of special pages?
*/
- var $mAllowSpecialInclusion;
+ public $mAllowSpecialInclusion;
/**
* Use tidy to cleanup output HTML?
*/
- var $mTidy = false;
+ public $mTidy = false;
/**
* Which lang to call for PLURAL and GRAMMAR
*/
- var $mInterfaceMessage = false;
+ public $mInterfaceMessage = false;
/**
* Overrides $mInterfaceMessage with arbitrary language
*/
- var $mTargetLanguage = null;
+ public $mTargetLanguage = null;
/**
* Maximum size of template expansions, in bytes
*/
- var $mMaxIncludeSize;
+ public $mMaxIncludeSize;
/**
* Maximum number of nodes touched by PPFrame::expand()
*/
- var $mMaxPPNodeCount;
+ public $mMaxPPNodeCount;
/**
* Maximum number of nodes generated by Preprocessor::preprocessToObj()
*/
- var $mMaxGeneratedPPNodeCount;
+ public $mMaxGeneratedPPNodeCount;
/**
* Maximum recursion depth in PPFrame::expand()
*/
- var $mMaxPPExpandDepth;
+ public $mMaxPPExpandDepth;
/**
* Maximum recursion depth for templates within templates
*/
- var $mMaxTemplateDepth;
+ public $mMaxTemplateDepth;
/**
* Maximum number of calls per parse to expensive parser functions
*/
- var $mExpensiveParserFunctionLimit;
+ public $mExpensiveParserFunctionLimit;
/**
* Remove HTML comments. ONLY APPLIES TO PREPROCESS OPERATIONS
*/
- var $mRemoveComments = true;
+ public $mRemoveComments = true;
/**
* Callback for template fetching. Used as first argument to call_user_func().
*/
- var $mTemplateCallback =
+ public $mTemplateCallback =
array( 'Parser', 'statelessFetchTemplate' );
/**
* Enable limit report in an HTML comment on output
*/
- var $mEnableLimitReport = false;
+ public $mEnableLimitReport = false;
/**
* Timestamp used for {{CURRENTDAY}} etc.
*/
- var $mTimestamp;
+ public $mTimestamp;
/**
* Target attribute for external links
*/
- var $mExternalLinkTarget;
+ public $mExternalLinkTarget;
/**
* Clean up signature texts?
@@ -142,37 +143,32 @@ class ParserOptions {
* 1) Strip ~~~, ~~~~ and ~~~~~ out of signatures
* 2) Substitute all transclusions
*/
- var $mCleanSignatures;
+ public $mCleanSignatures;
/**
* Transform wiki markup when saving the page?
*/
- var $mPreSaveTransform = true;
+ public $mPreSaveTransform = true;
/**
* Whether content conversion should be disabled
*/
- var $mDisableContentConversion;
+ public $mDisableContentConversion;
/**
* Whether title conversion should be disabled
*/
- var $mDisableTitleConversion;
+ public $mDisableTitleConversion;
/**
* Automatically number headings?
*/
- var $mNumberHeadings;
-
- /**
- * User math preference (as integer). Not used (1.19)
- */
- var $mMath;
+ public $mNumberHeadings;
/**
* Thumb size preferred by the user.
*/
- var $mThumbSize;
+ public $mThumbSize;
/**
* Maximum article size of an article to be marked as "stub"
@@ -182,90 +178,176 @@ class ParserOptions {
/**
* Language object of the User language.
*/
- var $mUserLang;
+ public $mUserLang;
/**
* @var User
* Stored user object
*/
- var $mUser;
+ public $mUser;
/**
* Parsing the page for a "preview" operation?
*/
- var $mIsPreview = false;
+ public $mIsPreview = false;
/**
* Parsing the page for a "preview" operation on a single section?
*/
- var $mIsSectionPreview = false;
+ public $mIsSectionPreview = false;
/**
* Parsing the printable version of the page?
*/
- var $mIsPrintable = false;
+ public $mIsPrintable = false;
/**
* Extra key that should be present in the caching key.
*/
- var $mExtraKey = '';
+ public $mExtraKey = '';
/**
* Function to be called when an option is accessed.
*/
protected $onAccessCallback = null;
- function getInterwikiMagic() { return $this->mInterwikiMagic; }
- function getAllowExternalImages() { return $this->mAllowExternalImages; }
- function getAllowExternalImagesFrom() { return $this->mAllowExternalImagesFrom; }
- function getEnableImageWhitelist() { return $this->mEnableImageWhitelist; }
- function getEditSection() { return $this->mEditSection; }
- function getNumberHeadings() { $this->optionUsed( 'numberheadings' );
- return $this->mNumberHeadings; }
- function getAllowSpecialInclusion() { return $this->mAllowSpecialInclusion; }
- function getTidy() { return $this->mTidy; }
- function getInterfaceMessage() { return $this->mInterfaceMessage; }
- function getTargetLanguage() { return $this->mTargetLanguage; }
- function getMaxIncludeSize() { return $this->mMaxIncludeSize; }
- function getMaxPPNodeCount() { return $this->mMaxPPNodeCount; }
- function getMaxGeneratedPPNodeCount() { return $this->mMaxGeneratedPPNodeCount; }
- function getMaxPPExpandDepth() { return $this->mMaxPPExpandDepth; }
- function getMaxTemplateDepth() { return $this->mMaxTemplateDepth; }
+ /**
+ * If the page being parsed is a redirect, this should hold the redirect
+ * target.
+ * @var Title|null
+ */
+ private $redirectTarget = null;
+
+ public function getInterwikiMagic() {
+ return $this->mInterwikiMagic;
+ }
+
+ public function getAllowExternalImages() {
+ return $this->mAllowExternalImages;
+ }
+
+ public function getAllowExternalImagesFrom() {
+ return $this->mAllowExternalImagesFrom;
+ }
+
+ public function getEnableImageWhitelist() {
+ return $this->mEnableImageWhitelist;
+ }
+
+ public function getEditSection() {
+ return $this->mEditSection;
+ }
+
+ public function getNumberHeadings() {
+ $this->optionUsed( 'numberheadings' );
+
+ return $this->mNumberHeadings;
+ }
+
+ public function getAllowSpecialInclusion() {
+ return $this->mAllowSpecialInclusion;
+ }
+
+ public function getTidy() {
+ return $this->mTidy;
+ }
+
+ public function getInterfaceMessage() {
+ return $this->mInterfaceMessage;
+ }
+
+ public function getTargetLanguage() {
+ return $this->mTargetLanguage;
+ }
+
+ public function getMaxIncludeSize() {
+ return $this->mMaxIncludeSize;
+ }
+
+ public function getMaxPPNodeCount() {
+ return $this->mMaxPPNodeCount;
+ }
+
+ public function getMaxGeneratedPPNodeCount() {
+ return $this->mMaxGeneratedPPNodeCount;
+ }
+
+ public function getMaxPPExpandDepth() {
+ return $this->mMaxPPExpandDepth;
+ }
+
+ public function getMaxTemplateDepth() {
+ return $this->mMaxTemplateDepth;
+ }
+
/* @since 1.20 */
- function getExpensiveParserFunctionLimit() { return $this->mExpensiveParserFunctionLimit; }
- function getRemoveComments() { return $this->mRemoveComments; }
- function getTemplateCallback() { return $this->mTemplateCallback; }
- function getEnableLimitReport() { return $this->mEnableLimitReport; }
- function getCleanSignatures() { return $this->mCleanSignatures; }
- function getExternalLinkTarget() { return $this->mExternalLinkTarget; }
- function getDisableContentConversion() { return $this->mDisableContentConversion; }
- function getDisableTitleConversion() { return $this->mDisableTitleConversion; }
- /** @deprecated since 1.22 use User::getOption('math') instead */
- function getMath() { $this->optionUsed( 'math' );
- return $this->mMath; }
- function getThumbSize() { $this->optionUsed( 'thumbsize' );
- return $this->mThumbSize; }
- function getStubThreshold() { $this->optionUsed( 'stubthreshold' );
- return $this->mStubThreshold; }
-
- function getIsPreview() { return $this->mIsPreview; }
- function getIsSectionPreview() { return $this->mIsSectionPreview; }
- function getIsPrintable() { $this->optionUsed( 'printable' );
- return $this->mIsPrintable; }
- function getUser() { return $this->mUser; }
- function getPreSaveTransform() { return $this->mPreSaveTransform; }
-
- /**
- * @param $title Title
- * @return Skin
- * @deprecated since 1.18 Use Linker::* instead
- */
- function getSkin( $title = null ) {
- wfDeprecated( __METHOD__, '1.18' );
- return new DummyLinker;
- }
-
- function getDateFormat() {
+ public function getExpensiveParserFunctionLimit() {
+ return $this->mExpensiveParserFunctionLimit;
+ }
+
+ public function getRemoveComments() {
+ return $this->mRemoveComments;
+ }
+
+ public function getTemplateCallback() {
+ return $this->mTemplateCallback;
+ }
+
+ public function getEnableLimitReport() {
+ return $this->mEnableLimitReport;
+ }
+
+ public function getCleanSignatures() {
+ return $this->mCleanSignatures;
+ }
+
+ public function getExternalLinkTarget() {
+ return $this->mExternalLinkTarget;
+ }
+
+ public function getDisableContentConversion() {
+ return $this->mDisableContentConversion;
+ }
+
+ public function getDisableTitleConversion() {
+ return $this->mDisableTitleConversion;
+ }
+
+ public function getThumbSize() {
+ $this->optionUsed( 'thumbsize' );
+
+ return $this->mThumbSize;
+ }
+
+ public function getStubThreshold() {
+ $this->optionUsed( 'stubthreshold' );
+
+ return $this->mStubThreshold;
+ }
+
+ public function getIsPreview() {
+ return $this->mIsPreview;
+ }
+
+ public function getIsSectionPreview() {
+ return $this->mIsSectionPreview;
+ }
+
+ public function getIsPrintable() {
+ $this->optionUsed( 'printable' );
+
+ return $this->mIsPrintable;
+ }
+
+ public function getUser() {
+ return $this->mUser;
+ }
+
+ public function getPreSaveTransform() {
+ return $this->mPreSaveTransform;
+ }
+
+ public function getDateFormat() {
$this->optionUsed( 'dateformat' );
if ( !isset( $this->mDateFormat ) ) {
$this->mDateFormat = $this->mUser->getDatePreference();
@@ -273,7 +355,7 @@ class ParserOptions {
return $this->mDateFormat;
}
- function getTimestamp() {
+ public function getTimestamp() {
if ( !isset( $this->mTimestamp ) ) {
$this->mTimestamp = wfTimestampNow();
}
@@ -293,10 +375,10 @@ class ParserOptions {
*
* {{int: }} uses this which used to produce inconsistent link tables (bug 14404).
*
- * @return Language object
+ * @return Language
* @since 1.19
*/
- function getUserLangObj() {
+ public function getUserLangObj() {
$this->optionUsed( 'userlang' );
return $this->mUserLang;
}
@@ -304,70 +386,180 @@ class ParserOptions {
/**
* Same as getUserLangObj() but returns a string instead.
*
- * @return String Language code
+ * @return string Language code
* @since 1.17
*/
- function getUserLang() {
+ public function getUserLang() {
return $this->getUserLangObj()->getCode();
}
- function setInterwikiMagic( $x ) { return wfSetVar( $this->mInterwikiMagic, $x ); }
- function setAllowExternalImages( $x ) { return wfSetVar( $this->mAllowExternalImages, $x ); }
- function setAllowExternalImagesFrom( $x ) { return wfSetVar( $this->mAllowExternalImagesFrom, $x ); }
- function setEnableImageWhitelist( $x ) { return wfSetVar( $this->mEnableImageWhitelist, $x ); }
- function setDateFormat( $x ) { return wfSetVar( $this->mDateFormat, $x ); }
- function setEditSection( $x ) { return wfSetVar( $this->mEditSection, $x ); }
- function setNumberHeadings( $x ) { return wfSetVar( $this->mNumberHeadings, $x ); }
- function setAllowSpecialInclusion( $x ) { return wfSetVar( $this->mAllowSpecialInclusion, $x ); }
- function setTidy( $x ) { return wfSetVar( $this->mTidy, $x ); }
-
- /** @deprecated in 1.19 */
- function setSkin( $x ) { wfDeprecated( __METHOD__, '1.19' ); }
- function setInterfaceMessage( $x ) { return wfSetVar( $this->mInterfaceMessage, $x ); }
- function setTargetLanguage( $x ) { return wfSetVar( $this->mTargetLanguage, $x, true ); }
- function setMaxIncludeSize( $x ) { return wfSetVar( $this->mMaxIncludeSize, $x ); }
- function setMaxPPNodeCount( $x ) { return wfSetVar( $this->mMaxPPNodeCount, $x ); }
- function setMaxGeneratedPPNodeCount( $x ) { return wfSetVar( $this->mMaxGeneratedPPNodeCount, $x ); }
- function setMaxTemplateDepth( $x ) { return wfSetVar( $this->mMaxTemplateDepth, $x ); }
+ public function setInterwikiMagic( $x ) {
+ return wfSetVar( $this->mInterwikiMagic, $x );
+ }
+
+ public function setAllowExternalImages( $x ) {
+ return wfSetVar( $this->mAllowExternalImages, $x );
+ }
+
+ public function setAllowExternalImagesFrom( $x ) {
+ return wfSetVar( $this->mAllowExternalImagesFrom, $x );
+ }
+
+ public function setEnableImageWhitelist( $x ) {
+ return wfSetVar( $this->mEnableImageWhitelist, $x );
+ }
+
+ public function setDateFormat( $x ) {
+ return wfSetVar( $this->mDateFormat, $x );
+ }
+
+ public function setEditSection( $x ) {
+ return wfSetVar( $this->mEditSection, $x );
+ }
+
+ public function setNumberHeadings( $x ) {
+ return wfSetVar( $this->mNumberHeadings, $x );
+ }
+
+ public function setAllowSpecialInclusion( $x ) {
+ return wfSetVar( $this->mAllowSpecialInclusion, $x );
+ }
+
+ public function setTidy( $x ) {
+ return wfSetVar( $this->mTidy, $x );
+ }
+
+ public function setInterfaceMessage( $x ) {
+ return wfSetVar( $this->mInterfaceMessage, $x );
+ }
+
+ public function setTargetLanguage( $x ) {
+ return wfSetVar( $this->mTargetLanguage, $x, true );
+ }
+
+ public function setMaxIncludeSize( $x ) {
+ return wfSetVar( $this->mMaxIncludeSize, $x );
+ }
+
+ public function setMaxPPNodeCount( $x ) {
+ return wfSetVar( $this->mMaxPPNodeCount, $x );
+ }
+
+ public function setMaxGeneratedPPNodeCount( $x ) {
+ return wfSetVar( $this->mMaxGeneratedPPNodeCount, $x );
+ }
+
+ public function setMaxTemplateDepth( $x ) {
+ return wfSetVar( $this->mMaxTemplateDepth, $x );
+ }
+
/* @since 1.20 */
- function setExpensiveParserFunctionLimit( $x ) { return wfSetVar( $this->mExpensiveParserFunctionLimit, $x ); }
- function setRemoveComments( $x ) { return wfSetVar( $this->mRemoveComments, $x ); }
- function setTemplateCallback( $x ) { return wfSetVar( $this->mTemplateCallback, $x ); }
- function enableLimitReport( $x = true ) { return wfSetVar( $this->mEnableLimitReport, $x ); }
- function setTimestamp( $x ) { return wfSetVar( $this->mTimestamp, $x ); }
- function setCleanSignatures( $x ) { return wfSetVar( $this->mCleanSignatures, $x ); }
- function setExternalLinkTarget( $x ) { return wfSetVar( $this->mExternalLinkTarget, $x ); }
- function disableContentConversion( $x = true ) { return wfSetVar( $this->mDisableContentConversion, $x ); }
- function disableTitleConversion( $x = true ) { return wfSetVar( $this->mDisableTitleConversion, $x ); }
- /** @deprecated since 1.22 */
- function setMath( $x ) { return wfSetVar( $this->mMath, $x ); }
- function setUserLang( $x ) {
+ public function setExpensiveParserFunctionLimit( $x ) {
+ return wfSetVar( $this->mExpensiveParserFunctionLimit, $x );
+ }
+
+ public function setRemoveComments( $x ) {
+ return wfSetVar( $this->mRemoveComments, $x );
+ }
+
+ public function setTemplateCallback( $x ) {
+ return wfSetVar( $this->mTemplateCallback, $x );
+ }
+
+ public function enableLimitReport( $x = true ) {
+ return wfSetVar( $this->mEnableLimitReport, $x );
+ }
+
+ public function setTimestamp( $x ) {
+ return wfSetVar( $this->mTimestamp, $x );
+ }
+
+ public function setCleanSignatures( $x ) {
+ return wfSetVar( $this->mCleanSignatures, $x );
+ }
+
+ public function setExternalLinkTarget( $x ) {
+ return wfSetVar( $this->mExternalLinkTarget, $x );
+ }
+
+ public function disableContentConversion( $x = true ) {
+ return wfSetVar( $this->mDisableContentConversion, $x );
+ }
+
+ public function disableTitleConversion( $x = true ) {
+ return wfSetVar( $this->mDisableTitleConversion, $x );
+ }
+
+ public function setUserLang( $x ) {
if ( is_string( $x ) ) {
$x = Language::factory( $x );
}
+
return wfSetVar( $this->mUserLang, $x );
}
- function setThumbSize( $x ) { return wfSetVar( $this->mThumbSize, $x ); }
- function setStubThreshold( $x ) { return wfSetVar( $this->mStubThreshold, $x ); }
- function setPreSaveTransform( $x ) { return wfSetVar( $this->mPreSaveTransform, $x ); }
- function setIsPreview( $x ) { return wfSetVar( $this->mIsPreview, $x ); }
- function setIsSectionPreview( $x ) { return wfSetVar( $this->mIsSectionPreview, $x ); }
- function setIsPrintable( $x ) { return wfSetVar( $this->mIsPrintable, $x ); }
+ public function setThumbSize( $x ) {
+ return wfSetVar( $this->mThumbSize, $x );
+ }
+
+ public function setStubThreshold( $x ) {
+ return wfSetVar( $this->mStubThreshold, $x );
+ }
+
+ public function setPreSaveTransform( $x ) {
+ return wfSetVar( $this->mPreSaveTransform, $x );
+ }
+
+ public function setIsPreview( $x ) {
+ return wfSetVar( $this->mIsPreview, $x );
+ }
+
+ public function setIsSectionPreview( $x ) {
+ return wfSetVar( $this->mIsSectionPreview, $x );
+ }
+
+ public function setIsPrintable( $x ) {
+ return wfSetVar( $this->mIsPrintable, $x );
+ }
+
+ /**
+ * Set the redirect target.
+ *
+ * Note that setting or changing this does not *make* the page a redirect
+ * or change its target, it merely records the information for reference
+ * during the parse.
+ *
+ * @since 1.24
+ * @param Title|null $title
+ */
+ function setRedirectTarget( $title ) {
+ $this->redirectTarget = $title;
+ }
+
+ /**
+ * Get the previously-set redirect target.
+ *
+ * @since 1.24
+ * @return Title|null
+ */
+ function getRedirectTarget() {
+ return $this->redirectTarget;
+ }
/**
* Extra key that should be present in the parser cache key.
+ * @param string $key
*/
- function addExtraKey( $key ) {
+ public function addExtraKey( $key ) {
$this->mExtraKey .= '!' . $key;
}
/**
* Constructor
- * @param $user User object
- * @param $lang Language object
+ * @param User $user
+ * @param Language $lang
*/
- function __construct( $user = null, $lang = null ) {
+ public function __construct( $user = null, $lang = null ) {
if ( $user === null ) {
global $wgUser;
if ( $wgUser === null ) {
@@ -390,8 +582,8 @@ class ParserOptions {
* Get a ParserOptions object from a given user.
* Language will be taken from $wgLang.
*
- * @param $user User object
- * @return ParserOptions object
+ * @param User $user
+ * @return ParserOptions
*/
public static function newFromUser( $user ) {
return new ParserOptions( $user );
@@ -400,9 +592,9 @@ class ParserOptions {
/**
* Get a ParserOptions object from a given user and language
*
- * @param $user User object
- * @param $lang Language object
- * @return ParserOptions object
+ * @param User $user
+ * @param Language $lang
+ * @return ParserOptions
*/
public static function newFromUserAndLang( User $user, Language $lang ) {
return new ParserOptions( $user, $lang );
@@ -411,8 +603,8 @@ class ParserOptions {
/**
* Get a ParserOptions object from a IContextSource object
*
- * @param $context IContextSource object
- * @return ParserOptions object
+ * @param IContextSource $context
+ * @return ParserOptions
*/
public static function newFromContext( IContextSource $context ) {
return new ParserOptions( $context->getUser(), $context->getLanguage() );
@@ -421,8 +613,8 @@ class ParserOptions {
/**
* Get user options
*
- * @param $user User object
- * @param $lang Language object
+ * @param User $user
+ * @param Language $lang
*/
private function initialiseFromUser( $user, $lang ) {
global $wgInterwikiMagic, $wgAllowExternalImages,
@@ -451,7 +643,6 @@ class ParserOptions {
$this->mUser = $user;
$this->mNumberHeadings = $user->getOption( 'numberheadings' );
- $this->mMath = $user->getOption( 'math' );
$this->mThumbSize = $user->getOption( 'thumbsize' );
$this->mStubThreshold = $user->getStubThreshold();
$this->mUserLang = $lang;
@@ -462,15 +653,17 @@ class ParserOptions {
/**
* Registers a callback for tracking which ParserOptions which are used.
* This is a private API with the parser.
+ * @param callable $callback
*/
- function registerWatcher( $callback ) {
+ public function registerWatcher( $callback ) {
$this->onAccessCallback = $callback;
}
/**
* Called when an option is accessed.
+ * @param string $optionName Name of the option
*/
- protected function optionUsed( $optionName ) {
+ public function optionUsed( $optionName ) {
if ( $this->onAccessCallback ) {
call_user_func( $this->onAccessCallback, $optionName );
}
@@ -483,37 +676,39 @@ class ParserOptions {
* @return array
*/
public static function legacyOptions() {
- return array( 'math', 'stubthreshold', 'numberheadings', 'userlang', 'thumbsize', 'editsection', 'printable' );
+ return array(
+ 'stubthreshold',
+ 'numberheadings',
+ 'userlang',
+ 'thumbsize',
+ 'editsection',
+ 'printable'
+ );
}
/**
* Generate a hash string with the values set on these ParserOptions
* for the keys given in the array.
* This will be used as part of the hash key for the parser cache,
- * so users sharign the options with vary for the same page share
+ * so users sharing the options with vary for the same page share
* the same cached data safely.
*
- * Replaces User::getPageRenderingHash()
- *
* Extensions which require it should install 'PageRenderingHash' hook,
* which will give them a chance to modify this key based on their own
* settings.
*
* @since 1.17
- * @param $forOptions Array
- * @param $title Title: used to get the content language of the page (since r97636)
+ * @param array $forOptions
+ * @param Title $title Used to get the content language of the page (since r97636)
* @return string Page rendering hash
*/
public function optionsHash( $forOptions, $title = null ) {
global $wgRenderHashAppend;
- $confstr = '';
-
- if ( in_array( 'math', $forOptions ) ) {
- $confstr .= $this->mMath;
- } else {
- $confstr .= '*';
- }
+ // FIXME: Once the cache key is reorganized this argument
+ // can be dropped. It was used when the math extension was
+ // part of core.
+ $confstr = '*';
// Space assigned for the stubthreshold but unused
// since it disables the parser cache, its value will always
@@ -573,7 +768,7 @@ class ParserOptions {
// Give a chance for extensions to modify the hash, if they have
// extra options or other effects on the parser cache.
- wfRunHooks( 'PageRenderingHash', array( &$confstr ) );
+ wfRunHooks( 'PageRenderingHash', array( &$confstr, $this->getUser(), &$forOptions ) );
// Make it a valid memcached key fragment
$confstr = str_replace( ' ', '_', $confstr );
diff --git a/includes/parser/ParserOutput.php b/includes/parser/ParserOutput.php
index 460f3211..5037ce18 100644
--- a/includes/parser/ParserOutput.php
+++ b/includes/parser/ParserOutput.php
@@ -22,7 +22,7 @@
* @ingroup Parser
*/
class ParserOutput extends CacheTime {
- var $mText, # The output text
+ public $mText, # The output text
$mLanguageLinks, # List of the full text of language links, in the order they appear
$mCategories, # Map of category names to sort keys
$mTitleText, # title text of the chosen language variant
@@ -41,6 +41,7 @@ class ParserOutput extends CacheTime {
$mModuleScripts = array(), # Modules of which only the JS will be loaded by the resource loader
$mModuleStyles = array(), # Modules of which only the CSSS will be loaded by the resource loader
$mModuleMessages = array(), # Modules of which only the messages will be loaded by the resource loader
+ $mJsConfigVars = array(), # JavaScript config variable for mw.config combined with this page
$mOutputHooks = array(), # Hook tags as per $wgParserOutputHooks
$mWarnings = array(), # Warning text to be returned to the user. Wikitext formatted, in the key only
$mSections = array(), # Table of contents
@@ -49,19 +50,20 @@ class ParserOutput extends CacheTime {
$mTOCHTML = '', # HTML of the TOC
$mTimestamp, # Timestamp of the revision
$mTOCEnabled = true; # Whether TOC should be shown, can't override __NOTOC__
- private $mIndexPolicy = ''; # 'index' or 'noindex'? Any other value will result in no change.
- private $mAccessedOptions = array(); # List of ParserOptions (stored in the keys)
- private $mSecondaryDataUpdates = array(); # List of DataUpdate, used to save info from the page somewhere else.
- private $mExtensionData = array(); # extra data used by extensions
- private $mLimitReportData = array(); # Parser limit report data
- private $mParseStartTime = array(); # Timestamps for getTimeSinceStart()
- private $mPreventClickjacking = false; # Whether to emit X-Frame-Options: DENY
-
- const EDITSECTION_REGEX = '#<(?:mw:)?editsection page="(.*?)" section="(.*?)"(?:/>|>(.*?)(</(?:mw:)?editsection>))#';
-
- function __construct( $text = '', $languageLinks = array(), $categoryLinks = array(),
- $containsOldMagic = false, $titletext = '' )
- {
+ private $mIndexPolicy = ''; # 'index' or 'noindex'? Any other value will result in no change.
+ private $mAccessedOptions = array(); # List of ParserOptions (stored in the keys)
+ private $mSecondaryDataUpdates = array(); # List of DataUpdate, used to save info from the page somewhere else.
+ private $mExtensionData = array(); # extra data used by extensions
+ private $mLimitReportData = array(); # Parser limit report data
+ private $mParseStartTime = array(); # Timestamps for getTimeSinceStart()
+ private $mPreventClickjacking = false; # Whether to emit X-Frame-Options: DENY
+
+ const EDITSECTION_REGEX =
+ '#<(?:mw:)?editsection page="(.*?)" section="(.*?)"(?:/>|>(.*?)(</(?:mw:)?editsection>))#';
+
+ public function __construct( $text = '', $languageLinks = array(), $categoryLinks = array(),
+ $containsOldMagic = false, $titletext = ''
+ ) {
$this->mText = $text;
$this->mLanguageLinks = $languageLinks;
$this->mCategories = $categoryLinks;
@@ -69,12 +71,31 @@ class ParserOutput extends CacheTime {
$this->mTitleText = $titletext;
}
- function getText() {
+ public function getText() {
wfProfileIn( __METHOD__ );
$text = $this->mText;
if ( $this->mEditSectionTokens ) {
- $text = preg_replace_callback( ParserOutput::EDITSECTION_REGEX,
- array( &$this, 'replaceEditSectionLinksCallback' ), $text );
+ $text = preg_replace_callback(
+ ParserOutput::EDITSECTION_REGEX,
+ function ( $m ) {
+ global $wgOut, $wgLang;
+ $editsectionPage = Title::newFromText( htmlspecialchars_decode( $m[1] ) );
+ $editsectionSection = htmlspecialchars_decode( $m[2] );
+ $editsectionContent = isset( $m[4] ) ? $m[3] : null;
+
+ if ( !is_object( $editsectionPage ) ) {
+ throw new MWException( "Bad parser output text." );
+ }
+
+ $skin = $wgOut->getSkin();
+ return call_user_func_array(
+ array( $skin, 'doEditSectionLink' ),
+ array( $editsectionPage, $editsectionSection,
+ $editsectionContent, $wgLang->getCode() )
+ );
+ },
+ $text
+ );
} else {
$text = preg_replace( ParserOutput::EDITSECTION_REGEX, '', $text );
}
@@ -84,7 +105,7 @@ class ParserOutput extends CacheTime {
$text = str_replace( array( Parser::TOC_START, Parser::TOC_END ), '', $text );
} else {
$text = preg_replace(
- '#'. preg_quote( Parser::TOC_START ) . '.*?' . preg_quote( Parser::TOC_END ) . '#s',
+ '#' . preg_quote( Parser::TOC_START ) . '.*?' . preg_quote( Parser::TOC_END ) . '#s',
'',
$text
);
@@ -93,97 +114,192 @@ class ParserOutput extends CacheTime {
return $text;
}
- /**
- * callback used by getText to replace editsection tokens
- * @private
- * @param $m
- * @throws MWException
- * @return mixed
- */
- function replaceEditSectionLinksCallback( $m ) {
- global $wgOut, $wgLang;
- $args = array(
- htmlspecialchars_decode( $m[1] ),
- htmlspecialchars_decode( $m[2] ),
- isset( $m[4] ) ? $m[3] : null,
- );
- $args[0] = Title::newFromText( $args[0] );
- if ( !is_object( $args[0] ) ) {
- throw new MWException( "Bad parser output text." );
- }
- $args[] = $wgLang->getCode();
- $skin = $wgOut->getSkin();
- return call_user_func_array( array( $skin, 'doEditSectionLink' ), $args );
- }
-
- function &getLanguageLinks() { return $this->mLanguageLinks; }
- function getInterwikiLinks() { return $this->mInterwikiLinks; }
- function getCategoryLinks() { return array_keys( $this->mCategories ); }
- function &getCategories() { return $this->mCategories; }
- function getTitleText() { return $this->mTitleText; }
- function getSections() { return $this->mSections; }
- function getEditSectionTokens() { return $this->mEditSectionTokens; }
- function &getLinks() { return $this->mLinks; }
- function &getTemplates() { return $this->mTemplates; }
- function &getTemplateIds() { return $this->mTemplateIds; }
- function &getImages() { return $this->mImages; }
- function &getFileSearchOptions() { return $this->mFileSearchOptions; }
- function &getExternalLinks() { return $this->mExternalLinks; }
- function getNoGallery() { return $this->mNoGallery; }
- function getHeadItems() { return $this->mHeadItems; }
- function getModules() { return $this->mModules; }
- function getModuleScripts() { return $this->mModuleScripts; }
- function getModuleStyles() { return $this->mModuleStyles; }
- function getModuleMessages() { return $this->mModuleMessages; }
- function getOutputHooks() { return (array)$this->mOutputHooks; }
- function getWarnings() { return array_keys( $this->mWarnings ); }
- function getIndexPolicy() { return $this->mIndexPolicy; }
- function getTOCHTML() { return $this->mTOCHTML; }
- function getTimestamp() { return $this->mTimestamp; }
- function getLimitReportData() { return $this->mLimitReportData; }
- function getTOCEnabled() { return $this->mTOCEnabled; }
-
- function setText( $text ) { return wfSetVar( $this->mText, $text ); }
- function setLanguageLinks( $ll ) { return wfSetVar( $this->mLanguageLinks, $ll ); }
- function setCategoryLinks( $cl ) { return wfSetVar( $this->mCategories, $cl ); }
-
- function setTitleText( $t ) { return wfSetVar( $this->mTitleText, $t ); }
- function setSections( $toc ) { return wfSetVar( $this->mSections, $toc ); }
- function setEditSectionTokens( $t ) { return wfSetVar( $this->mEditSectionTokens, $t ); }
- function setIndexPolicy( $policy ) { return wfSetVar( $this->mIndexPolicy, $policy ); }
- function setTOCHTML( $tochtml ) { return wfSetVar( $this->mTOCHTML, $tochtml ); }
- function setTimestamp( $timestamp ) { return wfSetVar( $this->mTimestamp, $timestamp ); }
- function setTOCEnabled( $flag ) { return wfSetVar( $this->mTOCEnabled, $flag ); }
-
- function addCategory( $c, $sort ) { $this->mCategories[$c] = $sort; }
- function addLanguageLink( $t ) { $this->mLanguageLinks[] = $t; }
- function addWarning( $s ) { $this->mWarnings[$s] = 1; }
-
- function addOutputHook( $hook, $data = false ) {
+ public function &getLanguageLinks() {
+ return $this->mLanguageLinks;
+ }
+
+ public function getInterwikiLinks() {
+ return $this->mInterwikiLinks;
+ }
+
+ public function getCategoryLinks() {
+ return array_keys( $this->mCategories );
+ }
+
+ public function &getCategories() {
+ return $this->mCategories;
+ }
+
+ public function getTitleText() {
+ return $this->mTitleText;
+ }
+
+ public function getSections() {
+ return $this->mSections;
+ }
+
+ public function getEditSectionTokens() {
+ return $this->mEditSectionTokens;
+ }
+
+ public function &getLinks() {
+ return $this->mLinks;
+ }
+
+ public function &getTemplates() {
+ return $this->mTemplates;
+ }
+
+ public function &getTemplateIds() {
+ return $this->mTemplateIds;
+ }
+
+ public function &getImages() {
+ return $this->mImages;
+ }
+
+ public function &getFileSearchOptions() {
+ return $this->mFileSearchOptions;
+ }
+
+ public function &getExternalLinks() {
+ return $this->mExternalLinks;
+ }
+
+ public function getNoGallery() {
+ return $this->mNoGallery;
+ }
+
+ public function getHeadItems() {
+ return $this->mHeadItems;
+ }
+
+ public function getModules() {
+ return $this->mModules;
+ }
+
+ public function getModuleScripts() {
+ return $this->mModuleScripts;
+ }
+
+ public function getModuleStyles() {
+ return $this->mModuleStyles;
+ }
+
+ public function getModuleMessages() {
+ return $this->mModuleMessages;
+ }
+
+ /** @since 1.23 */
+ public function getJsConfigVars() {
+ return $this->mJsConfigVars;
+ }
+
+ public function getOutputHooks() {
+ return (array)$this->mOutputHooks;
+ }
+
+ public function getWarnings() {
+ return array_keys( $this->mWarnings );
+ }
+
+ public function getIndexPolicy() {
+ return $this->mIndexPolicy;
+ }
+
+ public function getTOCHTML() {
+ return $this->mTOCHTML;
+ }
+
+ public function getTimestamp() {
+ return $this->mTimestamp;
+ }
+
+ public function getLimitReportData() {
+ return $this->mLimitReportData;
+ }
+
+ public function getTOCEnabled() {
+ return $this->mTOCEnabled;
+ }
+
+ public function setText( $text ) {
+ return wfSetVar( $this->mText, $text );
+ }
+
+ public function setLanguageLinks( $ll ) {
+ return wfSetVar( $this->mLanguageLinks, $ll );
+ }
+
+ public function setCategoryLinks( $cl ) {
+ return wfSetVar( $this->mCategories, $cl );
+ }
+
+ public function setTitleText( $t ) {
+ return wfSetVar( $this->mTitleText, $t );
+ }
+
+ public function setSections( $toc ) {
+ return wfSetVar( $this->mSections, $toc );
+ }
+
+ public function setEditSectionTokens( $t ) {
+ return wfSetVar( $this->mEditSectionTokens, $t );
+ }
+
+ public function setIndexPolicy( $policy ) {
+ return wfSetVar( $this->mIndexPolicy, $policy );
+ }
+
+ public function setTOCHTML( $tochtml ) {
+ return wfSetVar( $this->mTOCHTML, $tochtml );
+ }
+
+ public function setTimestamp( $timestamp ) {
+ return wfSetVar( $this->mTimestamp, $timestamp );
+ }
+
+ public function setTOCEnabled( $flag ) {
+ return wfSetVar( $this->mTOCEnabled, $flag );
+ }
+
+ public function addCategory( $c, $sort ) {
+ $this->mCategories[$c] = $sort;
+ }
+
+ public function addLanguageLink( $t ) {
+ $this->mLanguageLinks[] = $t;
+ }
+
+ public function addWarning( $s ) {
+ $this->mWarnings[$s] = 1;
+ }
+
+ public function addOutputHook( $hook, $data = false ) {
$this->mOutputHooks[] = array( $hook, $data );
}
- function setNewSection( $value ) {
+ public function setNewSection( $value ) {
$this->mNewSection = (bool)$value;
}
- function hideNewSection( $value ) {
+ public function hideNewSection( $value ) {
$this->mHideNewSection = (bool)$value;
}
- function getHideNewSection() {
+ public function getHideNewSection() {
return (bool)$this->mHideNewSection;
}
- function getNewSection() {
+ public function getNewSection() {
return (bool)$this->mNewSection;
}
/**
* Checks, if a url is pointing to the own server
*
- * @param string $internal the server to check against
- * @param string $url the url to check
+ * @param string $internal The server to check against
+ * @param string $url The url to check
* @return bool
*/
- static function isLinkInternal( $internal, $url ) {
+ public static function isLinkInternal( $internal, $url ) {
return (bool)preg_match( '/^' .
# If server is proto relative, check also for http/https links
( substr( $internal, 0, 2 ) === '//' ? '(?:https?:)?' : '' ) .
@@ -194,7 +310,7 @@ class ParserOutput extends CacheTime {
);
}
- function addExternalLink( $url ) {
+ public function addExternalLink( $url ) {
# We don't register links pointing to our own server, unless... :-)
global $wgServer, $wgRegisterInternalExternals;
@@ -210,10 +326,10 @@ class ParserOutput extends CacheTime {
/**
* Record a local or interwiki inline link for saving in future link tables.
*
- * @param $title Title object
- * @param $id Mixed: optional known page_id so we can skip the lookup
+ * @param Title $title
+ * @param int|null $id Optional known page_id so we can skip the lookup
*/
- function addLink( Title $title, $id = null ) {
+ public function addLink( Title $title, $id = null ) {
if ( $title->isExternal() ) {
// Don't record interwikis in pagelinks
$this->addInterwikiLink( $title );
@@ -245,10 +361,10 @@ class ParserOutput extends CacheTime {
* Register a file dependency for this output
* @param string $name Title dbKey
* @param string $timestamp MW timestamp of file creation (or false if non-existing)
- * @param string $sha1 base 36 SHA-1 of file (or false if non-existing)
+ * @param string $sha1 Base 36 SHA-1 of file (or false if non-existing)
* @return void
*/
- function addImage( $name, $timestamp = null, $sha1 = null ) {
+ public function addImage( $name, $timestamp = null, $sha1 = null ) {
$this->mImages[$name] = 1;
if ( $timestamp !== null && $sha1 !== null ) {
$this->mFileSearchOptions[$name] = array( 'time' => $timestamp, 'sha1' => $sha1 );
@@ -257,12 +373,12 @@ class ParserOutput extends CacheTime {
/**
* Register a template dependency for this output
- * @param $title Title
- * @param $page_id
- * @param $rev_id
+ * @param Title $title
+ * @param int $page_id
+ * @param int $rev_id
* @return void
*/
- function addTemplate( $title, $page_id, $rev_id ) {
+ public function addTemplate( $title, $page_id, $rev_id ) {
$ns = $title->getNamespace();
$dbk = $title->getDBkey();
if ( !isset( $this->mTemplates[$ns] ) ) {
@@ -276,14 +392,14 @@ class ParserOutput extends CacheTime {
}
/**
- * @param $title Title object, must be an interwiki link
- * @throws MWException if given invalid input
+ * @param Title $title Title object, must be an interwiki link
+ * @throws MWException If given invalid input
*/
- function addInterwikiLink( $title ) {
- $prefix = $title->getInterwiki();
- if ( $prefix == '' ) {
+ public function addInterwikiLink( $title ) {
+ if ( !$title->isExternal() ) {
throw new MWException( 'Non-interwiki link passed, internal parser error.' );
}
+ $prefix = $title->getInterwiki();
if ( !isset( $this->mInterwikiLinks[$prefix] ) ) {
$this->mInterwikiLinks[$prefix] = array();
}
@@ -294,8 +410,10 @@ class ParserOutput extends CacheTime {
* Add some text to the "<head>".
* If $tag is set, the section with that tag will only be included once
* in a given page.
+ * @param string $section
+ * @param string|bool $tag
*/
- function addHeadItem( $section, $tag = false ) {
+ public function addHeadItem( $section, $tag = false ) {
if ( $tag !== false ) {
$this->mHeadItems[$tag] = $section;
} else {
@@ -320,15 +438,34 @@ class ParserOutput extends CacheTime {
}
/**
+ * Add one or more variables to be set in mw.config in JavaScript.
+ *
+ * @param string|array $keys Key or array of key/value pairs.
+ * @param mixed $value [optional] Value of the configuration variable.
+ * @since 1.23
+ */
+ public function addJsConfigVars( $keys, $value = null ) {
+ if ( is_array( $keys ) ) {
+ foreach ( $keys as $key => $value ) {
+ $this->mJsConfigVars[$key] = $value;
+ }
+ return;
+ }
+
+ $this->mJsConfigVars[$keys] = $value;
+ }
+
+ /**
* Copy items from the OutputPage object into this one
*
- * @param $out OutputPage object
+ * @param OutputPage $out
*/
public function addOutputPageMetadata( OutputPage $out ) {
$this->addModules( $out->getModules() );
$this->addModuleScripts( $out->getModuleScripts() );
$this->addModuleStyles( $out->getModuleStyles() );
$this->addModuleMessages( $out->getModuleMessages() );
+ $this->addJsConfigVars( $out->getJsConfigVars() );
$this->mHeadItems = array_merge( $this->mHeadItems, $out->getHeadItemsArray() );
$this->mPreventClickjacking = $this->mPreventClickjacking || $out->getPreventClickjacking();
@@ -339,7 +476,7 @@ class ParserOutput extends CacheTime {
* -- this is assumed to have been validated
* (check equal normalisation, etc.)
*
- * @param string $text desired title text
+ * @param string $text Desired title text
*/
public function setDisplayTitle( $text ) {
$this->setTitleText( $text );
@@ -349,7 +486,7 @@ class ParserOutput extends CacheTime {
/**
* Get the title to be used for display
*
- * @return String
+ * @return string
*/
public function getDisplayTitle() {
$t = $this->getTitleText();
@@ -361,6 +498,7 @@ class ParserOutput extends CacheTime {
/**
* Fairly generic flag setter thingy.
+ * @param string $flag
*/
public function setFlag( $flag ) {
$this->mFlags[$flag] = true;
@@ -378,6 +516,9 @@ class ParserOutput extends CacheTime {
* retrieved given the page ID or via a DB join when given the page
* title.
*
+ * Since 1.23, page_props are also indexed by numeric value, to allow
+ * for efficient "top k" queries of pages wrt a given property.
+ *
* setProperty() is thus used to propagate properties from the parsed
* page to request contexts other than a page view of the currently parsed
* article.
@@ -395,10 +536,10 @@ class ParserOutput extends CacheTime {
* Wikimedia Commons.
* This is not actually implemented, yet but would be pretty cool.
*
- * @note: Do not use setProperty() to set a property which is only used
+ * @note Do not use setProperty() to set a property which is only used
* in a context where the ParserOutput object itself is already available,
* for example a normal page view. There is no need to save such a property
- * in the database since it the text is already parsed. You can just hook
+ * in the database since the text is already parsed. You can just hook
* OutputPageParserOutput and get your data out of the ParserOutput object.
*
* If you are writing an extension where you want to set a property in the
@@ -431,10 +572,22 @@ class ParserOutput extends CacheTime {
$this->mProperties[$name] = $value;
}
+ /**
+ * @param string $name The property name to look up.
+ *
+ * @return mixed|bool The value previously set using setProperty(). False if null or no value
+ * was set for the given property name.
+ *
+ * @note You need to use getProperties() to check for boolean and null properties.
+ */
public function getProperty( $name ) {
return isset( $this->mProperties[$name] ) ? $this->mProperties[$name] : false;
}
+ public function unsetProperty( $name ) {
+ unset( $this->mProperties[$name] );
+ }
+
public function getProperties() {
if ( !isset( $this->mProperties ) ) {
$this->mProperties = array();
@@ -445,7 +598,7 @@ class ParserOutput extends CacheTime {
/**
* Returns the options from its ParserOptions which have been taken
* into account to produce this output or false if not available.
- * @return mixed Array
+ * @return array
*/
public function getUsedOptions() {
if ( !isset( $this->mAccessedOptions ) ) {
@@ -455,16 +608,24 @@ class ParserOutput extends CacheTime {
}
/**
- * Callback passed by the Parser to the ParserOptions to keep track of which options are used.
- * @access private
+ * Tags a parser option for use in the cache key for this parser output.
+ * Registered as a watcher at ParserOptions::registerWatcher() by Parser::clearState().
+ *
+ * @see ParserCache::getKey
+ * @see ParserCache::save
+ * @see ParserOptions::addExtraKey
+ * @see ParserOptions::optionsHash
+ * @param string $option
*/
- function recordOption( $option ) {
+ public function recordOption( $option ) {
$this->mAccessedOptions[$option] = true;
}
/**
- * Adds an update job to the output. Any update jobs added to the output will eventually bexecuted in order to
- * store any secondary information extracted from the page's content.
+ * Adds an update job to the output. Any update jobs added to the output will
+ * eventually be executed in order to store any secondary information extracted
+ * from the page's content. This is triggered by calling getSecondaryDataUpdates()
+ * and is used for forward links updates on edit and backlink updates by jobs.
*
* @since 1.20
*
@@ -479,16 +640,16 @@ class ParserOutput extends CacheTime {
* extracted from the page's content, including a LinksUpdate object for all links stored in
* this ParserOutput object.
*
- * @note: Avoid using this method directly, use ContentHandler::getSecondaryDataUpdates() instead! The content
- * handler may provide additional update objects.
+ * @note Avoid using this method directly, use ContentHandler::getSecondaryDataUpdates()
+ * instead! The content handler may provide additional update objects.
*
* @since 1.20
*
- * @param $title Title The title of the page we're updating. If not given, a title object will be created
- * based on $this->getTitleText()
- * @param $recursive Boolean: queue jobs for recursive updates?
+ * @param Title $title The title of the page we're updating. If not given, a title object will
+ * be created based on $this->getTitleText()
+ * @param bool $recursive Queue jobs for recursive updates?
*
- * @return Array. An array of instances of DataUpdate
+ * @return array An array of instances of DataUpdate
*/
public function getSecondaryDataUpdates( Title $title = null, $recursive = true ) {
if ( is_null( $title ) ) {
@@ -535,11 +696,10 @@ class ParserOutput extends CacheTime {
* @since 1.21
*
* @param string $key The key for accessing the data. Extensions should take care to avoid
- * conflicts in naming keys. It is suggested to use the extension's name as a
- * prefix.
+ * conflicts in naming keys. It is suggested to use the extension's name as a prefix.
*
* @param mixed $value The value to set. Setting a value to null is equivalent to removing
- * the value.
+ * the value.
*/
public function setExtensionData( $key, $value ) {
if ( $value === null ) {
@@ -557,7 +717,7 @@ class ParserOutput extends CacheTime {
*
* @param string $key The key to look up.
*
- * @return mixed The value previously set for the given key using setExtensionData( $key ),
+ * @return mixed|null The value previously set for the given key using setExtensionData()
* or null if no value was set for this key.
*/
public function getExtensionData( $key ) {
@@ -573,10 +733,12 @@ class ParserOutput extends CacheTime {
if ( !$clock || $clock === 'wall' ) {
$ret['wall'] = microtime( true );
}
- if ( ( !$clock || $clock === 'cpu' ) && function_exists( 'getrusage' ) ) {
- $ru = getrusage();
- $ret['cpu'] = $ru['ru_utime.tv_sec'] + $ru['ru_utime.tv_usec'] / 1e6;
- $ret['cpu'] += $ru['ru_stime.tv_sec'] + $ru['ru_stime.tv_usec'] / 1e6;
+ if ( !$clock || $clock === 'cpu' ) {
+ $ru = wfGetRusage();
+ if ( $ru ) {
+ $ret['cpu'] = $ru['ru_utime.tv_sec'] + $ru['ru_utime.tv_usec'] / 1e6;
+ $ret['cpu'] += $ru['ru_stime.tv_sec'] + $ru['ru_stime.tv_usec'] / 1e6;
+ }
}
return $ret;
}
@@ -585,7 +747,7 @@ class ParserOutput extends CacheTime {
* Resets the parse start timestamps for future calls to getTimeSinceStart()
* @since 1.22
*/
- function resetParseStartTime() {
+ public function resetParseStartTime() {
$this->mParseStartTime = self::getTimes();
}
@@ -600,7 +762,7 @@ class ParserOutput extends CacheTime {
* @param string $clock
* @return float|null
*/
- function getTimeSinceStart( $clock ) {
+ public function getTimeSinceStart( $clock ) {
if ( !isset( $this->mParseStartTime[$clock] ) ) {
return null;
}
@@ -628,7 +790,7 @@ class ParserOutput extends CacheTime {
* @param string $key Message key
* @param mixed $value Appropriate for Message::params()
*/
- function setLimitReportData( $key, $value ) {
+ public function setLimitReportData( $key, $value ) {
$this->mLimitReportData[$key] = $value;
}
@@ -636,10 +798,21 @@ class ParserOutput extends CacheTime {
* Get or set the prevent-clickjacking flag
*
* @since 1.24
- * @param boolean|null $flag New flag value, or null to leave it unchanged
- * @return boolean Old flag value
+ * @param bool|null $flag New flag value, or null to leave it unchanged
+ * @return bool Old flag value
*/
public function preventClickjacking( $flag = null ) {
return wfSetVar( $this->mPreventClickjacking, $flag );
}
+
+ /**
+ * Save space for for serialization by removing useless values
+ * @return array
+ */
+ public function __sleep() {
+ return array_diff(
+ array_keys( get_object_vars( $this ) ),
+ array( 'mSecondaryDataUpdates', 'mParseStartTime' )
+ );
+ }
}
diff --git a/includes/parser/Preprocessor.php b/includes/parser/Preprocessor.php
index aeacd2e1..b32593c9 100644
--- a/includes/parser/Preprocessor.php
+++ b/includes/parser/Preprocessor.php
@@ -28,42 +28,44 @@ interface Preprocessor {
/**
* Create a new preprocessor object based on an initialised Parser object
*
- * @param $parser Parser
+ * @param Parser $parser
*/
- function __construct( $parser );
+ public function __construct( $parser );
/**
* Create a new top-level frame for expansion of a page
*
* @return PPFrame
*/
- function newFrame();
+ public function newFrame();
/**
- * Create a new custom frame for programmatic use of parameter replacement as used in some extensions
+ * Create a new custom frame for programmatic use of parameter replacement
+ * as used in some extensions.
*
- * @param $args array
+ * @param array $args
*
* @return PPFrame
*/
- function newCustomFrame( $args );
+ public function newCustomFrame( $args );
/**
- * Create a new custom node for programmatic use of parameter replacement as used in some extensions
+ * Create a new custom node for programmatic use of parameter replacement
+ * as used in some extensions.
*
- * @param $values
+ * @param array $values
*/
- function newPartNodeArray( $values );
+ public function newPartNodeArray( $values );
/**
* Preprocess text to a PPNode
*
- * @param $text
- * @param $flags
+ * @param string $text
+ * @param int $flags
*
* @return PPNode
*/
- function preprocessToObj( $text, $flags = 0 );
+ public function preprocessToObj( $text, $flags = 0 );
}
/**
@@ -75,8 +77,9 @@ interface PPFrame {
const STRIP_COMMENTS = 4;
const NO_IGNORE = 8;
const RECOVER_COMMENTS = 16;
+ const NO_TAGS = 32;
- const RECOVER_ORIG = 27; // = 1|2|8|16 no constant expression support in PHP yet
+ const RECOVER_ORIG = 59; // = 1|2|8|16|32 no constant expression support in PHP yet
/** This constant exists when $indexOffset is supported in newChild() */
const SUPPORTS_INDEX_OFFSET = 1;
@@ -84,87 +87,168 @@ interface PPFrame {
/**
* Create a child frame
*
- * @param array $args
- * @param Title $title
+ * @param array|bool $args
+ * @param bool|Title $title
* @param int $indexOffset A number subtracted from the index attributes of the arguments
*
* @return PPFrame
*/
- function newChild( $args = false, $title = false, $indexOffset = 0 );
+ public function newChild( $args = false, $title = false, $indexOffset = 0 );
+
+ /**
+ * Expand a document tree node, caching the result on its parent with the given key
+ * @param string|int $key
+ * @param string|PPNode $root
+ * @param int $flags
+ * @return string
+ */
+ public function cachedExpand( $key, $root, $flags = 0 );
/**
* Expand a document tree node
+ * @param string|PPNode $root
+ * @param int $flags
+ * @return string
*/
- function expand( $root, $flags = 0 );
+ public function expand( $root, $flags = 0 );
/**
* Implode with flags for expand()
+ * @param string $sep
+ * @param int $flags
+ * @param string|PPNode $args,...
+ * @return string
*/
- function implodeWithFlags( $sep, $flags /*, ... */ );
+ public function implodeWithFlags( $sep, $flags /*, ... */ );
/**
* Implode with no flags specified
+ * @param string $sep
+ * @param string|PPNode $args,...
+ * @return string
*/
- function implode( $sep /*, ... */ );
+ public function implode( $sep /*, ... */ );
/**
* Makes an object that, when expand()ed, will be the same as one obtained
* with implode()
+ * @param string $sep
+ * @param string|PPNode $args,...
+ * @return PPNode
*/
- function virtualImplode( $sep /*, ... */ );
+ public function virtualImplode( $sep /*, ... */ );
/**
* Virtual implode with brackets
+ * @param string $start
+ * @param string $sep
+ * @param string $end
+ * @param string|PPNode $args,...
+ * @return PPNode
*/
- function virtualBracketedImplode( $start, $sep, $end /*, ... */ );
+ public function virtualBracketedImplode( $start, $sep, $end /*, ... */ );
/**
* Returns true if there are no arguments in this frame
*
* @return bool
*/
- function isEmpty();
+ public function isEmpty();
/**
* Returns all arguments of this frame
+ * @return array
*/
- function getArguments();
+ public function getArguments();
/**
* Returns all numbered arguments of this frame
+ * @return array
*/
- function getNumberedArguments();
+ public function getNumberedArguments();
/**
* Returns all named arguments of this frame
+ * @return array
*/
- function getNamedArguments();
+ public function getNamedArguments();
/**
* Get an argument to this frame by name
+ * @param string $name
+ * @return bool
*/
- function getArgument( $name );
+ public function getArgument( $name );
/**
* Returns true if the infinite loop check is OK, false if a loop is detected
*
- * @param $title
- *
+ * @param Title $title
* @return bool
*/
- function loopCheck( $title );
+ public function loopCheck( $title );
/**
* Return true if the frame is a template frame
+ * @return bool
*/
- function isTemplate();
+ public function isTemplate();
+
+ /**
+ * Set the "volatile" flag.
+ *
+ * Note that this is somewhat of a "hack" in order to make extensions
+ * with side effects (such as Cite) work with the PHP parser. New
+ * extensions should be written in a way that they do not need this
+ * function, because other parsers (such as Parsoid) are not guaranteed
+ * to respect it, and it may be removed in the future.
+ *
+ * @param bool $flag
+ */
+ public function setVolatile( $flag = true );
+
+ /**
+ * Get the "volatile" flag.
+ *
+ * Callers should avoid caching the result of an expansion if it has the
+ * volatile flag set.
+ *
+ * @see self::setVolatile()
+ * @return bool
+ */
+ public function isVolatile();
+
+ /**
+ * Get the TTL of the frame's output.
+ *
+ * This is the maximum amount of time, in seconds, that this frame's
+ * output should be cached for. A value of null indicates that no
+ * maximum has been specified.
+ *
+ * Note that this TTL only applies to caching frames as parts of pages.
+ * It is not relevant to caching the entire rendered output of a page.
+ *
+ * @return int|null
+ */
+ public function getTTL();
+
+ /**
+ * Set the TTL of the output of this frame and all of its ancestors.
+ * Has no effect if the new TTL is greater than the one already set.
+ * Note that it is the caller's responsibility to change the cache
+ * expiry of the page as a whole, if such behavior is desired.
+ *
+ * @see self::getTTL()
+ * @param int $ttl
+ */
+ public function setTTL( $ttl );
/**
* Get a title of frame
*
* @return Title
*/
- function getTitle();
+ public function getTitle();
}
/**
@@ -184,36 +268,42 @@ interface PPNode {
/**
* Get an array-type node containing the children of this node.
* Returns false if this is not a tree node.
+ * @return PPNode
*/
- function getChildren();
+ public function getChildren();
/**
* Get the first child of a tree node. False if there isn't one.
*
* @return PPNode
*/
- function getFirstChild();
+ public function getFirstChild();
/**
* Get the next sibling of any node. False if there isn't one
+ * @return PPNode
*/
- function getNextSibling();
+ public function getNextSibling();
/**
* Get all children of this tree node which have a given name.
* Returns an array-type node, or false if this is not a tree node.
+ * @param string $type
+ * @return bool|PPNode
*/
- function getChildrenOfType( $type );
+ public function getChildrenOfType( $type );
/**
* Returns the length of the array, or false if this is not an array-type node
*/
- function getLength();
+ public function getLength();
/**
* Returns an item of an array-type node
+ * @param int $i
+ * @return bool|PPNode
*/
- function item( $i );
+ public function item( $i );
/**
* Get the name of this node. The following names are defined here:
@@ -226,25 +316,29 @@ interface PPNode {
* #nodelist An array-type node
*
* The subclass may define various other names for tree and leaf nodes.
+ * @return string
*/
- function getName();
+ public function getName();
/**
* Split a "<part>" node into an associative array containing:
* name PPNode name
* index String index
* value PPNode value
+ * @return array
*/
- function splitArg();
+ public function splitArg();
/**
* Split an "<ext>" node into an associative array containing name, attr, inner and close
* All values in the resulting array are PPNodes. Inner and close are optional.
+ * @return array
*/
- function splitExt();
+ public function splitExt();
/**
* Split an "<h>" node
+ * @return array
*/
- function splitHeading();
+ public function splitHeading();
}
diff --git a/includes/parser/Preprocessor_DOM.php b/includes/parser/Preprocessor_DOM.php
index 3138f483..2edb79a2 100644
--- a/includes/parser/Preprocessor_DOM.php
+++ b/includes/parser/Preprocessor_DOM.php
@@ -23,19 +23,21 @@
/**
* @ingroup Parser
+ * @codingStandardsIgnoreStart
*/
class Preprocessor_DOM implements Preprocessor {
+ // @codingStandardsIgnoreEnd
/**
* @var Parser
*/
- var $parser;
+ public $parser;
- var $memoryLimit;
+ public $memoryLimit;
const CACHE_VERSION = 1;
- function __construct( $parser ) {
+ public function __construct( $parser ) {
$this->parser = $parser;
$mem = ini_get( 'memory_limit' );
$this->memoryLimit = false;
@@ -51,40 +53,57 @@ class Preprocessor_DOM implements Preprocessor {
/**
* @return PPFrame_DOM
*/
- function newFrame() {
+ public function newFrame() {
return new PPFrame_DOM( $this );
}
/**
- * @param $args array
+ * @param array $args
* @return PPCustomFrame_DOM
*/
- function newCustomFrame( $args ) {
+ public function newCustomFrame( $args ) {
return new PPCustomFrame_DOM( $this, $args );
}
/**
- * @param $values
+ * @param array $values
* @return PPNode_DOM
*/
- function newPartNodeArray( $values ) {
+ public function newPartNodeArray( $values ) {
//NOTE: DOM manipulation is slower than building & parsing XML! (or so Tim sais)
$xml = "<list>";
foreach ( $values as $k => $val ) {
if ( is_int( $k ) ) {
- $xml .= "<part><name index=\"$k\"/><value>" . htmlspecialchars( $val ) . "</value></part>";
+ $xml .= "<part><name index=\"$k\"/><value>"
+ . htmlspecialchars( $val ) . "</value></part>";
} else {
- $xml .= "<part><name>" . htmlspecialchars( $k ) . "</name>=<value>" . htmlspecialchars( $val ) . "</value></part>";
+ $xml .= "<part><name>" . htmlspecialchars( $k )
+ . "</name>=<value>" . htmlspecialchars( $val ) . "</value></part>";
}
}
$xml .= "</list>";
+ wfProfileIn( __METHOD__ . '-loadXML' );
$dom = new DOMDocument();
- $dom->loadXML( $xml );
- $root = $dom->documentElement;
+ wfSuppressWarnings();
+ $result = $dom->loadXML( $xml );
+ wfRestoreWarnings();
+ if ( !$result ) {
+ // Try running the XML through UtfNormal to get rid of invalid characters
+ $xml = UtfNormal::cleanUp( $xml );
+ // 1 << 19 == XML_PARSE_HUGE, needed so newer versions of libxml2
+ // don't barf when the XML is >256 levels deep
+ $result = $dom->loadXML( $xml, 1 << 19 );
+ }
+ wfProfileOut( __METHOD__ . '-loadXML' );
+ if ( !$result ) {
+ throw new MWException( 'Parameters passed to ' . __METHOD__ . ' result in invalid XML' );
+ }
+
+ $root = $dom->documentElement;
$node = new PPNode_DOM( $root->childNodes );
return $node;
}
@@ -93,7 +112,7 @@ class Preprocessor_DOM implements Preprocessor {
* @throws MWException
* @return bool
*/
- function memCheck() {
+ public function memCheck() {
if ( $this->memoryLimit === false ) {
return true;
}
@@ -109,10 +128,11 @@ class Preprocessor_DOM implements Preprocessor {
* Preprocess some wikitext and return the document tree.
* This is the ghost of Parser::replace_variables().
*
- * @param string $text the text to parse
- * @param $flags Integer: bitwise combination of:
- * Parser::PTD_FOR_INCLUSION Handle "<noinclude>" and "<includeonly>" as if the text is being
- * included. Default is to assume a direct page view.
+ * @param string $text The text to parse
+ * @param int $flags Bitwise combination of:
+ * Parser::PTD_FOR_INCLUSION Handle "<noinclude>" and "<includeonly>"
+ * as if the text is being included. Default
+ * is to assume a direct page view.
*
* The generated DOM tree must depend only on the input text and the flags.
* The DOM tree must be the same in OT_HTML and OT_WIKI mode, to avoid a regression of bug 4899.
@@ -128,7 +148,7 @@ class Preprocessor_DOM implements Preprocessor {
* @throws MWException
* @return PPNode_DOM
*/
- function preprocessToObj( $text, $flags = 0 ) {
+ public function preprocessToObj( $text, $flags = 0 ) {
wfProfileIn( __METHOD__ );
global $wgMemc, $wgPreprocessorCacheThreshold;
@@ -160,7 +180,6 @@ class Preprocessor_DOM implements Preprocessor {
$xml = $this->preprocessToXml( $text, $flags );
}
-
// Fail if the number of elements exceeds acceptable limits
// Do not attempt to generate the DOM
$this->parser->mGeneratedPPNodeCount += substr_count( $xml, '<' );
@@ -181,7 +200,8 @@ class Preprocessor_DOM implements Preprocessor {
if ( !$result ) {
// Try running the XML through UtfNormal to get rid of invalid characters
$xml = UtfNormal::cleanUp( $xml );
- // 1 << 19 == XML_PARSE_HUGE, needed so newer versions of libxml2 don't barf when the XML is >256 levels deep
+ // 1 << 19 == XML_PARSE_HUGE, needed so newer versions of libxml2
+ // don't barf when the XML is >256 levels deep.
$result = $dom->loadXML( $xml, 1 << 19 );
}
if ( $result ) {
@@ -202,11 +222,11 @@ class Preprocessor_DOM implements Preprocessor {
}
/**
- * @param $text string
- * @param $flags int
+ * @param string $text
+ * @param int $flags
* @return string
*/
- function preprocessToXml( $text, $flags = 0 ) {
+ public function preprocessToXml( $text, $flags = 0 ) {
wfProfileIn( __METHOD__ );
$rules = array(
'{' => array(
@@ -234,7 +254,9 @@ class Preprocessor_DOM implements Preprocessor {
$ignoredTags = array( 'includeonly', '/includeonly' );
$ignoredElements = array( 'noinclude' );
$xmlishElements[] = 'noinclude';
- if ( strpos( $text, '<onlyinclude>' ) !== false && strpos( $text, '</onlyinclude>' ) !== false ) {
+ if ( strpos( $text, '<onlyinclude>' ) !== false
+ && strpos( $text, '</onlyinclude>' ) !== false
+ ) {
$enableOnlyinclude = true;
}
} else {
@@ -250,19 +272,28 @@ class Preprocessor_DOM implements Preprocessor {
$stack = new PPDStack;
$searchBase = "[{<\n"; #}
- $revText = strrev( $text ); // For fast reverse searches
+ // For fast reverse searches
+ $revText = strrev( $text );
$lengthText = strlen( $text );
- $i = 0; # Input pointer, starts out pointing to a pseudo-newline before the start
- $accum =& $stack->getAccum(); # Current accumulator
+ // Input pointer, starts out pointing to a pseudo-newline before the start
+ $i = 0;
+ // Current accumulator
+ $accum =& $stack->getAccum();
$accum = '<root>';
- $findEquals = false; # True to find equals signs in arguments
- $findPipe = false; # True to take notice of pipe characters
+ // True to find equals signs in arguments
+ $findEquals = false;
+ // True to take notice of pipe characters
+ $findPipe = false;
$headingIndex = 1;
- $inHeading = false; # True if $i is inside a possible heading
- $noMoreGT = false; # True if there are no more greater-than (>) signs right of $i
- $findOnlyinclude = $enableOnlyinclude; # True to ignore all input up to the next <onlyinclude>
- $fakeLineStart = true; # Do a line-start run without outputting an LF character
+ // True if $i is inside a possible heading
+ $inHeading = false;
+ // True if there are no more greater-than (>) signs right of $i
+ $noMoreGT = false;
+ // True to ignore all input up to the next <onlyinclude>
+ $findOnlyinclude = $enableOnlyinclude;
+ // Do a line-start run without outputting an LF character
+ $fakeLineStart = true;
while ( true ) {
//$this->memCheck();
@@ -347,7 +378,9 @@ class Preprocessor_DOM implements Preprocessor {
if ( $found == 'angle' ) {
$matches = false;
// Handle </onlyinclude>
- if ( $enableOnlyinclude && substr( $text, $i, strlen( '</onlyinclude>' ) ) == '</onlyinclude>' ) {
+ if ( $enableOnlyinclude
+ && substr( $text, $i, strlen( '</onlyinclude>' ) ) == '</onlyinclude>'
+ ) {
$findOnlyinclude = true;
continue;
}
@@ -400,14 +433,14 @@ class Preprocessor_DOM implements Preprocessor {
// the overall start. That's not how Sanitizer::removeHTMLcomments() did it, but
// it's a possible beneficial b/c break.
if ( $wsStart > 0 && substr( $text, $wsStart - 1, 1 ) == "\n"
- && substr( $text, $wsEnd + 1, 1 ) == "\n" )
- {
+ && substr( $text, $wsEnd + 1, 1 ) == "\n"
+ ) {
// Remove leading whitespace from the end of the accumulator
// Sanity check first though
$wsLength = $i - $wsStart;
if ( $wsLength > 0
- && strspn( $accum, " \t", -$wsLength ) === $wsLength )
- {
+ && strspn( $accum, " \t", -$wsLength ) === $wsLength
+ ) {
$accum = substr( $accum, 0, -$wsLength );
}
@@ -461,7 +494,9 @@ class Preprocessor_DOM implements Preprocessor {
// Handle ignored tags
if ( in_array( $lowerName, $ignoredTags ) ) {
- $accum .= '<ignore>' . htmlspecialchars( substr( $text, $i, $tagEndPos - $i + 1 ) ) . '</ignore>';
+ $accum .= '<ignore>'
+ . htmlspecialchars( substr( $text, $i, $tagEndPos - $i + 1 ) )
+ . '</ignore>';
$i = $tagEndPos + 1;
continue;
}
@@ -476,8 +511,8 @@ class Preprocessor_DOM implements Preprocessor {
$attrEnd = $tagEndPos;
// Find closing tag
if ( preg_match( "/<\/" . preg_quote( $name, '/' ) . "\s*>/i",
- $text, $matches, PREG_OFFSET_CAPTURE, $tagEndPos + 1 ) )
- {
+ $text, $matches, PREG_OFFSET_CAPTURE, $tagEndPos + 1 )
+ ) {
$inner = substr( $text, $tagEndPos + 1, $matches[0][1] - $tagEndPos - 1 );
$i = $matches[0][1] + strlen( $matches[0][0] );
$close = '<close>' . htmlspecialchars( $matches[0][0] ) . '</close>';
@@ -521,9 +556,11 @@ class Preprocessor_DOM implements Preprocessor {
$count = strspn( $text, '=', $i, 6 );
if ( $count == 1 && $findEquals ) {
- // DWIM: This looks kind of like a name/value separator
- // Let's let the equals handler have it and break the potential heading
- // This is heuristic, but AFAICT the methods for completely correct disambiguation are very complex.
+ // DWIM: This looks kind of like a name/value separator.
+ // Let's let the equals handler have it and break the
+ // potential heading. This is heuristic, but AFAICT the
+ // methods for completely correct disambiguation are very
+ // complex.
} elseif ( $count > 0 ) {
$piece = array(
'open' => "\n",
@@ -542,8 +579,9 @@ class Preprocessor_DOM implements Preprocessor {
// A heading must be open, otherwise \n wouldn't have been in the search list
assert( '$piece->open == "\n"' );
$part = $piece->getCurrentPart();
- // Search back through the input to see if it has a proper close
- // Do this using the reversed string since the other solutions (end anchor, etc.) are inefficient
+ // Search back through the input to see if it has a proper close.
+ // Do this using the reversed string since the other solutions
+ // (end anchor, etc.) are inefficient.
$wsLength = strspn( $revText, " \t", $lengthText - $i );
$searchStart = $i - $wsLength;
if ( isset( $part->commentEnd ) && $searchStart - 1 == $part->commentEnd ) {
@@ -737,18 +775,18 @@ class Preprocessor_DOM implements Preprocessor {
* @ingroup Parser
*/
class PPDStack {
- var $stack, $rootAccum;
+ public $stack, $rootAccum;
/**
* @var PPDStack
*/
- var $top;
- var $out;
- var $elementClass = 'PPDStackElement';
+ public $top;
+ public $out;
+ public $elementClass = 'PPDStackElement';
- static $false = false;
+ public static $false = false;
- function __construct() {
+ public function __construct() {
$this->stack = array();
$this->top = false;
$this->rootAccum = '';
@@ -758,15 +796,15 @@ class PPDStack {
/**
* @return int
*/
- function count() {
+ public function count() {
return count( $this->stack );
}
- function &getAccum() {
+ public function &getAccum() {
return $this->accum;
}
- function getCurrentPart() {
+ public function getCurrentPart() {
if ( $this->top === false ) {
return false;
} else {
@@ -774,7 +812,7 @@ class PPDStack {
}
}
- function push( $data ) {
+ public function push( $data ) {
if ( $data instanceof $this->elementClass ) {
$this->stack[] = $data;
} else {
@@ -785,7 +823,7 @@ class PPDStack {
$this->accum =& $this->top->getAccum();
}
- function pop() {
+ public function pop() {
if ( !count( $this->stack ) ) {
throw new MWException( __METHOD__ . ': no elements remaining' );
}
@@ -801,7 +839,7 @@ class PPDStack {
return $temp;
}
- function addPart( $s = '' ) {
+ public function addPart( $s = '' ) {
$this->top->addPart( $s );
$this->accum =& $this->top->getAccum();
}
@@ -809,7 +847,7 @@ class PPDStack {
/**
* @return array
*/
- function getFlags() {
+ public function getFlags() {
if ( !count( $this->stack ) ) {
return array(
'findEquals' => false,
@@ -826,15 +864,15 @@ class PPDStack {
* @ingroup Parser
*/
class PPDStackElement {
- var $open, // Opening character (\n for heading)
+ public $open, // Opening character (\n for heading)
$close, // Matching closing character
$count, // Number of opening characters found (number of "=" for heading)
$parts, // Array of PPDPart objects describing pipe-separated parts.
$lineStart; // True if the open char appeared at the start of the input line. Not set for headings.
- var $partClass = 'PPDPart';
+ public $partClass = 'PPDPart';
- function __construct( $data = array() ) {
+ public function __construct( $data = array() ) {
$class = $this->partClass;
$this->parts = array( new $class );
@@ -843,23 +881,23 @@ class PPDStackElement {
}
}
- function &getAccum() {
+ public function &getAccum() {
return $this->parts[count( $this->parts ) - 1]->out;
}
- function addPart( $s = '' ) {
+ public function addPart( $s = '' ) {
$class = $this->partClass;
$this->parts[] = new $class( $s );
}
- function getCurrentPart() {
+ public function getCurrentPart() {
return $this->parts[count( $this->parts ) - 1];
}
/**
* @return array
*/
- function getFlags() {
+ public function getFlags() {
$partCount = count( $this->parts );
$findPipe = $this->open != "\n" && $this->open != '[';
return array(
@@ -872,9 +910,10 @@ class PPDStackElement {
/**
* Get the output string that would result if the close is not found.
*
+ * @param bool|int $openingCount
* @return string
*/
- function breakSyntax( $openingCount = false ) {
+ public function breakSyntax( $openingCount = false ) {
if ( $this->open == "\n" ) {
$s = $this->parts[0]->out;
} else {
@@ -900,14 +939,14 @@ class PPDStackElement {
* @ingroup Parser
*/
class PPDPart {
- var $out; // Output accumulator string
+ public $out; // Output accumulator string
// Optional member variables:
// eqpos Position of equals sign in output accumulator
// commentEnd Past-the-end input pointer for the last comment encountered
// visualEnd Past-the-end input pointer for the end of the accumulator minus comments
- function __construct( $out = '' ) {
+ public function __construct( $out = '' ) {
$this->out = $out;
}
}
@@ -915,57 +954,71 @@ class PPDPart {
/**
* An expansion frame, used as a context to expand the result of preprocessToObj()
* @ingroup Parser
+ * @codingStandardsIgnoreStart
*/
class PPFrame_DOM implements PPFrame {
+ // @codingStandardsIgnoreEnd
/**
* @var Preprocessor
*/
- var $preprocessor;
+ public $preprocessor;
/**
* @var Parser
*/
- var $parser;
+ public $parser;
/**
* @var Title
*/
- var $title;
- var $titleCache;
+ public $title;
+ public $titleCache;
/**
* Hashtable listing templates which are disallowed for expansion in this frame,
* having been encountered previously in parent frames.
*/
- var $loopCheckHash;
+ public $loopCheckHash;
/**
* Recursion depth of this frame, top = 0
* Note that this is NOT the same as expansion depth in expand()
*/
- var $depth;
+ public $depth;
+
+ private $volatile = false;
+ private $ttl = null;
+
+ /**
+ * @var array
+ */
+ protected $childExpansionCache;
/**
* Construct a new preprocessor frame.
- * @param $preprocessor Preprocessor The parent preprocessor
+ * @param Preprocessor $preprocessor The parent preprocessor
*/
- function __construct( $preprocessor ) {
+ public function __construct( $preprocessor ) {
$this->preprocessor = $preprocessor;
$this->parser = $preprocessor->parser;
$this->title = $this->parser->mTitle;
$this->titleCache = array( $this->title ? $this->title->getPrefixedDBkey() : false );
$this->loopCheckHash = array();
$this->depth = 0;
+ $this->childExpansionCache = array();
}
/**
* Create a new child frame
* $args is optionally a multi-root PPNode or array containing the template arguments
*
+ * @param bool|array $args
+ * @param Title|bool $title
+ * @param int $indexOffset
* @return PPTemplateFrame_DOM
*/
- function newChild( $args = false, $title = false, $indexOffset = 0 ) {
+ public function newChild( $args = false, $title = false, $indexOffset = 0 ) {
$namedArgs = array();
$numberedArgs = array();
if ( $title === false ) {
@@ -980,7 +1033,7 @@ class PPFrame_DOM implements PPFrame {
if ( $arg instanceof PPNode ) {
$arg = $arg->node;
}
- if ( !$xpath ) {
+ if ( !$xpath || $xpath->document !== $arg->ownerDocument ) {
$xpath = new DOMXPath( $arg->ownerDocument );
}
@@ -1005,11 +1058,23 @@ class PPFrame_DOM implements PPFrame {
/**
* @throws MWException
- * @param $root
- * @param $flags int
+ * @param string|int $key
+ * @param string|PPNode_DOM|DOMDocument $root
+ * @param int $flags
+ * @return string
+ */
+ public function cachedExpand( $key, $root, $flags = 0 ) {
+ // we don't have a parent, so we don't have a cache
+ return $this->expand( $root, $flags );
+ }
+
+ /**
+ * @throws MWException
+ * @param string|PPNode_DOM|DOMDocument $root
+ * @param int $flags
* @return string
*/
- function expand( $root, $flags = 0 ) {
+ public function expand( $root, $flags = 0 ) {
static $expansionDepth = 0;
if ( is_string( $root ) ) {
return $root;
@@ -1142,17 +1207,16 @@ class PPFrame_DOM implements PPFrame {
# Remove it in HTML, pre+remove and STRIP_COMMENTS modes
if ( $this->parser->ot['html']
|| ( $this->parser->ot['pre'] && $this->parser->mOptions->getRemoveComments() )
- || ( $flags & PPFrame::STRIP_COMMENTS ) )
- {
+ || ( $flags & PPFrame::STRIP_COMMENTS )
+ ) {
$out .= '';
- }
- # Add a strip marker in PST mode so that pstPass2() can run some old-fashioned regexes on the result
- # Not in RECOVER_COMMENTS mode (extractSections) though
- elseif ( $this->parser->ot['wiki'] && !( $flags & PPFrame::RECOVER_COMMENTS ) ) {
+ } elseif ( $this->parser->ot['wiki'] && !( $flags & PPFrame::RECOVER_COMMENTS ) ) {
+ # Add a strip marker in PST mode so that pstPass2() can
+ # run some old-fashioned regexes on the result.
+ # Not in RECOVER_COMMENTS mode (extractSections) though.
$out .= $this->parser->insertStripItem( $contextNode->textContent );
- }
- # Recover the literal comment in RECOVER_COMMENTS and pre+no-remove
- else {
+ } else {
+ # Recover the literal comment in RECOVER_COMMENTS and pre+no-remove
$out .= $contextNode->textContent;
}
} elseif ( $contextNode->nodeName == 'ignore' ) {
@@ -1160,7 +1224,9 @@ class PPFrame_DOM implements PPFrame {
# OT_WIKI will only respect <ignore> in substed templates.
# The other output types respect it unless NO_IGNORE is set.
# extractSections() sets NO_IGNORE and so never respects it.
- if ( ( !isset( $this->parent ) && $this->parser->ot['wiki'] ) || ( $flags & PPFrame::NO_IGNORE ) ) {
+ if ( ( !isset( $this->parent ) && $this->parser->ot['wiki'] )
+ || ( $flags & PPFrame::NO_IGNORE )
+ ) {
$out .= $contextNode->textContent;
} else {
$out .= '';
@@ -1172,13 +1238,29 @@ class PPFrame_DOM implements PPFrame {
$attrs = $xpath->query( 'attr', $contextNode );
$inners = $xpath->query( 'inner', $contextNode );
$closes = $xpath->query( 'close', $contextNode );
- $params = array(
- 'name' => new PPNode_DOM( $names->item( 0 ) ),
- 'attr' => $attrs->length > 0 ? new PPNode_DOM( $attrs->item( 0 ) ) : null,
- 'inner' => $inners->length > 0 ? new PPNode_DOM( $inners->item( 0 ) ) : null,
- 'close' => $closes->length > 0 ? new PPNode_DOM( $closes->item( 0 ) ) : null,
- );
- $out .= $this->parser->extensionSubstitution( $params, $this );
+ if ( $flags & PPFrame::NO_TAGS ) {
+ $s = '<' . $this->expand( $names->item( 0 ), $flags );
+ if ( $attrs->length > 0 ) {
+ $s .= $this->expand( $attrs->item( 0 ), $flags );
+ }
+ if ( $inners->length > 0 ) {
+ $s .= '>' . $this->expand( $inners->item( 0 ), $flags );
+ if ( $closes->length > 0 ) {
+ $s .= $this->expand( $closes->item( 0 ), $flags );
+ }
+ } else {
+ $s .= '/>';
+ }
+ $out .= $s;
+ } else {
+ $params = array(
+ 'name' => new PPNode_DOM( $names->item( 0 ) ),
+ 'attr' => $attrs->length > 0 ? new PPNode_DOM( $attrs->item( 0 ) ) : null,
+ 'inner' => $inners->length > 0 ? new PPNode_DOM( $inners->item( 0 ) ) : null,
+ 'close' => $closes->length > 0 ? new PPNode_DOM( $closes->item( 0 ) ) : null,
+ );
+ $out .= $this->parser->extensionSubstitution( $params, $this );
+ }
} elseif ( $contextNode->nodeName == 'h' ) {
# Heading
$s = $this->expand( $contextNode->childNodes, $flags );
@@ -1231,11 +1313,12 @@ class PPFrame_DOM implements PPFrame {
}
/**
- * @param $sep
- * @param $flags
+ * @param string $sep
+ * @param int $flags
+ * @param string|PPNode_DOM|DOMDocument $args,...
* @return string
*/
- function implodeWithFlags( $sep, $flags /*, ... */ ) {
+ public function implodeWithFlags( $sep, $flags /*, ... */ ) {
$args = array_slice( func_get_args(), 2 );
$first = true;
@@ -1263,9 +1346,11 @@ class PPFrame_DOM implements PPFrame {
* Implode with no flags specified
* This previously called implodeWithFlags but has now been inlined to reduce stack depth
*
+ * @param string $sep
+ * @param string|PPNode_DOM|DOMDocument $args,...
* @return string
*/
- function implode( $sep /*, ... */ ) {
+ public function implode( $sep /*, ... */ ) {
$args = array_slice( func_get_args(), 1 );
$first = true;
@@ -1293,9 +1378,11 @@ class PPFrame_DOM implements PPFrame {
* Makes an object that, when expand()ed, will be the same as one obtained
* with implode()
*
+ * @param string $sep
+ * @param string|PPNode_DOM|DOMDocument $args,...
* @return array
*/
- function virtualImplode( $sep /*, ... */ ) {
+ public function virtualImplode( $sep /*, ... */ ) {
$args = array_slice( func_get_args(), 1 );
$out = array();
$first = true;
@@ -1321,9 +1408,13 @@ class PPFrame_DOM implements PPFrame {
/**
* Virtual implode with brackets
+ * @param string $start
+ * @param string $sep
+ * @param string $end
+ * @param string|PPNode_DOM|DOMDocument $args,...
* @return array
*/
- function virtualBracketedImplode( $start, $sep, $end /*, ... */ ) {
+ public function virtualBracketedImplode( $start, $sep, $end /*, ... */ ) {
$args = array_slice( func_get_args(), 3 );
$out = array( $start );
$first = true;
@@ -1348,11 +1439,11 @@ class PPFrame_DOM implements PPFrame {
return $out;
}
- function __toString() {
+ public function __toString() {
return 'frame{}';
}
- function getPDBK( $level = false ) {
+ public function getPDBK( $level = false ) {
if ( $level === false ) {
return $this->title->getPrefixedDBkey();
} else {
@@ -1363,21 +1454,21 @@ class PPFrame_DOM implements PPFrame {
/**
* @return array
*/
- function getArguments() {
+ public function getArguments() {
return array();
}
/**
* @return array
*/
- function getNumberedArguments() {
+ public function getNumberedArguments() {
return array();
}
/**
* @return array
*/
- function getNamedArguments() {
+ public function getNamedArguments() {
return array();
}
@@ -1386,20 +1477,21 @@ class PPFrame_DOM implements PPFrame {
*
* @return bool
*/
- function isEmpty() {
+ public function isEmpty() {
return true;
}
- function getArgument( $name ) {
+ public function getArgument( $name ) {
return false;
}
/**
* Returns true if the infinite loop check is OK, false if a loop is detected
*
+ * @param Title $title
* @return bool
*/
- function loopCheck( $title ) {
+ public function loopCheck( $title ) {
return !isset( $this->loopCheckHash[$title->getPrefixedDBkey()] );
}
@@ -1408,7 +1500,7 @@ class PPFrame_DOM implements PPFrame {
*
* @return bool
*/
- function isTemplate() {
+ public function isTemplate() {
return false;
}
@@ -1417,32 +1509,75 @@ class PPFrame_DOM implements PPFrame {
*
* @return Title
*/
- function getTitle() {
+ public function getTitle() {
return $this->title;
}
+
+ /**
+ * Set the volatile flag
+ *
+ * @param bool $flag
+ */
+ public function setVolatile( $flag = true ) {
+ $this->volatile = $flag;
+ }
+
+ /**
+ * Get the volatile flag
+ *
+ * @return bool
+ */
+ public function isVolatile() {
+ return $this->volatile;
+ }
+
+ /**
+ * Set the TTL
+ *
+ * @param int $ttl
+ */
+ public function setTTL( $ttl ) {
+ if ( $ttl !== null && ( $this->ttl === null || $ttl < $this->ttl ) ) {
+ $this->ttl = $ttl;
+ }
+ }
+
+ /**
+ * Get the TTL
+ *
+ * @return int|null
+ */
+ public function getTTL() {
+ return $this->ttl;
+ }
}
/**
* Expansion frame with template arguments
* @ingroup Parser
+ * @codingStandardsIgnoreStart
*/
class PPTemplateFrame_DOM extends PPFrame_DOM {
- var $numberedArgs, $namedArgs;
+ // @codingStandardsIgnoreEnd
+
+ public $numberedArgs, $namedArgs;
/**
* @var PPFrame_DOM
*/
- var $parent;
- var $numberedExpansionCache, $namedExpansionCache;
+ public $parent;
+ public $numberedExpansionCache, $namedExpansionCache;
/**
- * @param $preprocessor
- * @param $parent PPFrame_DOM
- * @param $numberedArgs array
- * @param $namedArgs array
- * @param $title Title
+ * @param Preprocessor $preprocessor
+ * @param bool|PPFrame_DOM $parent
+ * @param array $numberedArgs
+ * @param array $namedArgs
+ * @param bool|Title $title
*/
- function __construct( $preprocessor, $parent = false, $numberedArgs = array(), $namedArgs = array(), $title = false ) {
+ public function __construct( $preprocessor, $parent = false, $numberedArgs = array(),
+ $namedArgs = array(), $title = false
+ ) {
parent::__construct( $preprocessor );
$this->parent = $parent;
@@ -1460,7 +1595,7 @@ class PPTemplateFrame_DOM extends PPFrame_DOM {
$this->numberedExpansionCache = $this->namedExpansionCache = array();
}
- function __toString() {
+ public function __toString() {
$s = 'tplframe{';
$first = true;
$args = $this->numberedArgs + $this->namedArgs;
@@ -1478,15 +1613,33 @@ class PPTemplateFrame_DOM extends PPFrame_DOM {
}
/**
+ * @throws MWException
+ * @param string|int $key
+ * @param string|PPNode_DOM|DOMDocument $root
+ * @param int $flags
+ * @return string
+ */
+ public function cachedExpand( $key, $root, $flags = 0 ) {
+ if ( isset( $this->parent->childExpansionCache[$key] ) ) {
+ return $this->parent->childExpansionCache[$key];
+ }
+ $retval = $this->expand( $root, $flags );
+ if ( !$this->isVolatile() ) {
+ $this->parent->childExpansionCache[$key] = $retval;
+ }
+ return $retval;
+ }
+
+ /**
* Returns true if there are no arguments in this frame
*
* @return bool
*/
- function isEmpty() {
+ public function isEmpty() {
return !count( $this->numberedArgs ) && !count( $this->namedArgs );
}
- function getArguments() {
+ public function getArguments() {
$arguments = array();
foreach ( array_merge(
array_keys( $this->numberedArgs ),
@@ -1496,7 +1649,7 @@ class PPTemplateFrame_DOM extends PPFrame_DOM {
return $arguments;
}
- function getNumberedArguments() {
+ public function getNumberedArguments() {
$arguments = array();
foreach ( array_keys( $this->numberedArgs ) as $key ) {
$arguments[$key] = $this->getArgument( $key );
@@ -1504,7 +1657,7 @@ class PPTemplateFrame_DOM extends PPFrame_DOM {
return $arguments;
}
- function getNamedArguments() {
+ public function getNamedArguments() {
$arguments = array();
foreach ( array_keys( $this->namedArgs ) as $key ) {
$arguments[$key] = $this->getArgument( $key );
@@ -1512,18 +1665,21 @@ class PPTemplateFrame_DOM extends PPFrame_DOM {
return $arguments;
}
- function getNumberedArgument( $index ) {
+ public function getNumberedArgument( $index ) {
if ( !isset( $this->numberedArgs[$index] ) ) {
return false;
}
if ( !isset( $this->numberedExpansionCache[$index] ) ) {
# No trimming for unnamed arguments
- $this->numberedExpansionCache[$index] = $this->parent->expand( $this->numberedArgs[$index], PPFrame::STRIP_COMMENTS );
+ $this->numberedExpansionCache[$index] = $this->parent->expand(
+ $this->numberedArgs[$index],
+ PPFrame::STRIP_COMMENTS
+ );
}
return $this->numberedExpansionCache[$index];
}
- function getNamedArgument( $name ) {
+ public function getNamedArgument( $name ) {
if ( !isset( $this->namedArgs[$name] ) ) {
return false;
}
@@ -1535,7 +1691,7 @@ class PPTemplateFrame_DOM extends PPFrame_DOM {
return $this->namedExpansionCache[$name];
}
- function getArgument( $name ) {
+ public function getArgument( $name ) {
$text = $this->getNumberedArgument( $name );
if ( $text === false ) {
$text = $this->getNamedArgument( $name );
@@ -1548,24 +1704,37 @@ class PPTemplateFrame_DOM extends PPFrame_DOM {
*
* @return bool
*/
- function isTemplate() {
+ public function isTemplate() {
return true;
}
+
+ public function setVolatile( $flag = true ) {
+ parent::setVolatile( $flag );
+ $this->parent->setVolatile( $flag );
+ }
+
+ public function setTTL( $ttl ) {
+ parent::setTTL( $ttl );
+ $this->parent->setTTL( $ttl );
+ }
}
/**
* Expansion frame with custom arguments
* @ingroup Parser
+ * @codingStandardsIgnoreStart
*/
class PPCustomFrame_DOM extends PPFrame_DOM {
- var $args;
+ // @codingStandardsIgnoreEnd
+
+ public $args;
- function __construct( $preprocessor, $args ) {
+ public function __construct( $preprocessor, $args ) {
parent::__construct( $preprocessor );
$this->args = $args;
}
- function __toString() {
+ public function __toString() {
$s = 'cstmframe{';
$first = true;
foreach ( $this->args as $name => $value ) {
@@ -1584,48 +1753,50 @@ class PPCustomFrame_DOM extends PPFrame_DOM {
/**
* @return bool
*/
- function isEmpty() {
+ public function isEmpty() {
return !count( $this->args );
}
- function getArgument( $index ) {
+ public function getArgument( $index ) {
if ( !isset( $this->args[$index] ) ) {
return false;
}
return $this->args[$index];
}
- function getArguments() {
+ public function getArguments() {
return $this->args;
}
}
/**
* @ingroup Parser
+ * @codingStandardsIgnoreStart
*/
class PPNode_DOM implements PPNode {
+ // @codingStandardsIgnoreEnd
/**
* @var DOMElement
*/
- var $node;
- var $xpath;
+ public $node;
+ public $xpath;
- function __construct( $node, $xpath = false ) {
+ public function __construct( $node, $xpath = false ) {
$this->node = $node;
}
/**
* @return DOMXPath
*/
- function getXPath() {
+ public function getXPath() {
if ( $this->xpath === null ) {
$this->xpath = new DOMXPath( $this->node->ownerDocument );
}
return $this->xpath;
}
- function __toString() {
+ public function __toString() {
if ( $this->node instanceof DOMNodeList ) {
$s = '';
foreach ( $this->node as $node ) {
@@ -1640,37 +1811,37 @@ class PPNode_DOM implements PPNode {
/**
* @return bool|PPNode_DOM
*/
- function getChildren() {
+ public function getChildren() {
return $this->node->childNodes ? new self( $this->node->childNodes ) : false;
}
/**
* @return bool|PPNode_DOM
*/
- function getFirstChild() {
+ public function getFirstChild() {
return $this->node->firstChild ? new self( $this->node->firstChild ) : false;
}
/**
* @return bool|PPNode_DOM
*/
- function getNextSibling() {
+ public function getNextSibling() {
return $this->node->nextSibling ? new self( $this->node->nextSibling ) : false;
}
/**
- * @param $type
+ * @param string $type
*
* @return bool|PPNode_DOM
*/
- function getChildrenOfType( $type ) {
+ public function getChildrenOfType( $type ) {
return new self( $this->getXPath()->query( $type, $this->node ) );
}
/**
* @return int
*/
- function getLength() {
+ public function getLength() {
if ( $this->node instanceof DOMNodeList ) {
return $this->node->length;
} else {
@@ -1679,10 +1850,10 @@ class PPNode_DOM implements PPNode {
}
/**
- * @param $i
+ * @param int $i
* @return bool|PPNode_DOM
*/
- function item( $i ) {
+ public function item( $i ) {
$item = $this->node->item( $i );
return $item ? new self( $item ) : false;
}
@@ -1690,7 +1861,7 @@ class PPNode_DOM implements PPNode {
/**
* @return string
*/
- function getName() {
+ public function getName() {
if ( $this->node instanceof DOMNodeList ) {
return '#nodelist';
} else {
@@ -1707,7 +1878,7 @@ class PPNode_DOM implements PPNode {
* @throws MWException
* @return array
*/
- function splitArg() {
+ public function splitArg() {
$xpath = $this->getXPath();
$names = $xpath->query( 'name', $this->node );
$values = $xpath->query( 'value', $this->node );
@@ -1729,7 +1900,7 @@ class PPNode_DOM implements PPNode {
* @throws MWException
* @return array
*/
- function splitExt() {
+ public function splitExt() {
$xpath = $this->getXPath();
$names = $xpath->query( 'name', $this->node );
$attrs = $xpath->query( 'attr', $this->node );
@@ -1755,7 +1926,7 @@ class PPNode_DOM implements PPNode {
* @throws MWException
* @return array
*/
- function splitHeading() {
+ public function splitHeading() {
if ( $this->getName() !== 'h' ) {
throw new MWException( 'Invalid h node passed to ' . __METHOD__ );
}
diff --git a/includes/parser/Preprocessor_Hash.php b/includes/parser/Preprocessor_Hash.php
index 2fc5e118..63763967 100644
--- a/includes/parser/Preprocessor_Hash.php
+++ b/includes/parser/Preprocessor_Hash.php
@@ -26,39 +26,42 @@
* * attribute nodes are children
* * "<h>" nodes that aren't at the top are replaced with <possible-h>
* @ingroup Parser
+ * @codingStandardsIgnoreStart
*/
class Preprocessor_Hash implements Preprocessor {
+ // @codingStandardsIgnoreEnd
+
/**
* @var Parser
*/
- var $parser;
+ public $parser;
const CACHE_VERSION = 1;
- function __construct( $parser ) {
+ public function __construct( $parser ) {
$this->parser = $parser;
}
/**
* @return PPFrame_Hash
*/
- function newFrame() {
+ public function newFrame() {
return new PPFrame_Hash( $this );
}
/**
- * @param $args array
+ * @param array $args
* @return PPCustomFrame_Hash
*/
- function newCustomFrame( $args ) {
+ public function newCustomFrame( $args ) {
return new PPCustomFrame_Hash( $this, $args );
}
/**
- * @param $values array
+ * @param array $values
* @return PPNode_Hash_Array
*/
- function newPartNodeArray( $values ) {
+ public function newPartNodeArray( $values ) {
$list = array();
foreach ( $values as $k => $val ) {
@@ -89,10 +92,10 @@ class Preprocessor_Hash implements Preprocessor {
* Preprocess some wikitext and return the document tree.
* This is the ghost of Parser::replace_variables().
*
- * @param string $text the text to parse
- * @param $flags Integer: bitwise combination of:
- * Parser::PTD_FOR_INCLUSION Handle "<noinclude>" and "<includeonly>" as if the text is being
- * included. Default is to assume a direct page view.
+ * @param string $text The text to parse
+ * @param int $flags Bitwise combination of:
+ * Parser::PTD_FOR_INCLUSION Handle "<noinclude>" and "<includeonly>" as if the text is being
+ * included. Default is to assume a direct page view.
*
* The generated DOM tree must depend only on the input text and the flags.
* The DOM tree must be the same in OT_HTML and OT_WIKI mode, to avoid a regression of bug 4899.
@@ -108,13 +111,15 @@ class Preprocessor_Hash implements Preprocessor {
* @throws MWException
* @return PPNode_Hash_Tree
*/
- function preprocessToObj( $text, $flags = 0 ) {
+ public function preprocessToObj( $text, $flags = 0 ) {
wfProfileIn( __METHOD__ );
// Check cache.
global $wgMemc, $wgPreprocessorCacheThreshold;
- $cacheable = $wgPreprocessorCacheThreshold !== false && strlen( $text ) > $wgPreprocessorCacheThreshold;
+ $cacheable = $wgPreprocessorCacheThreshold !== false
+ && strlen( $text ) > $wgPreprocessorCacheThreshold;
+
if ( $cacheable ) {
wfProfileIn( __METHOD__ . '-cacheable' );
@@ -161,7 +166,9 @@ class Preprocessor_Hash implements Preprocessor {
$ignoredTags = array( 'includeonly', '/includeonly' );
$ignoredElements = array( 'noinclude' );
$xmlishElements[] = 'noinclude';
- if ( strpos( $text, '<onlyinclude>' ) !== false && strpos( $text, '</onlyinclude>' ) !== false ) {
+ if ( strpos( $text, '<onlyinclude>' ) !== false
+ && strpos( $text, '</onlyinclude>' ) !== false
+ ) {
$enableOnlyinclude = true;
}
} else {
@@ -177,18 +184,27 @@ class Preprocessor_Hash implements Preprocessor {
$stack = new PPDStack_Hash;
$searchBase = "[{<\n";
- $revText = strrev( $text ); // For fast reverse searches
+ // For fast reverse searches
+ $revText = strrev( $text );
$lengthText = strlen( $text );
- $i = 0; # Input pointer, starts out pointing to a pseudo-newline before the start
- $accum =& $stack->getAccum(); # Current accumulator
- $findEquals = false; # True to find equals signs in arguments
- $findPipe = false; # True to take notice of pipe characters
+ // Input pointer, starts out pointing to a pseudo-newline before the start
+ $i = 0;
+ // Current accumulator
+ $accum =& $stack->getAccum();
+ // True to find equals signs in arguments
+ $findEquals = false;
+ // True to take notice of pipe characters
+ $findPipe = false;
$headingIndex = 1;
- $inHeading = false; # True if $i is inside a possible heading
- $noMoreGT = false; # True if there are no more greater-than (>) signs right of $i
- $findOnlyinclude = $enableOnlyinclude; # True to ignore all input up to the next <onlyinclude>
- $fakeLineStart = true; # Do a line-start run without outputting an LF character
+ // True if $i is inside a possible heading
+ $inHeading = false;
+ // True if there are no more greater-than (>) signs right of $i
+ $noMoreGT = false;
+ // True to ignore all input up to the next <onlyinclude>
+ $findOnlyinclude = $enableOnlyinclude;
+ // Do a line-start run without outputting an LF character
+ $fakeLineStart = true;
while ( true ) {
//$this->memCheck();
@@ -273,7 +289,9 @@ class Preprocessor_Hash implements Preprocessor {
if ( $found == 'angle' ) {
$matches = false;
// Handle </onlyinclude>
- if ( $enableOnlyinclude && substr( $text, $i, strlen( '</onlyinclude>' ) ) == '</onlyinclude>' ) {
+ if ( $enableOnlyinclude
+ && substr( $text, $i, strlen( '</onlyinclude>' ) ) == '</onlyinclude>'
+ ) {
$findOnlyinclude = true;
continue;
}
@@ -326,15 +344,15 @@ class Preprocessor_Hash implements Preprocessor {
// the overall start. That's not how Sanitizer::removeHTMLcomments() did it, but
// it's a possible beneficial b/c break.
if ( $wsStart > 0 && substr( $text, $wsStart - 1, 1 ) == "\n"
- && substr( $text, $wsEnd + 1, 1 ) == "\n" )
- {
+ && substr( $text, $wsEnd + 1, 1 ) == "\n"
+ ) {
// Remove leading whitespace from the end of the accumulator
// Sanity check first though
$wsLength = $i - $wsStart;
if ( $wsLength > 0
&& $accum->lastNode instanceof PPNode_Hash_Text
- && strspn( $accum->lastNode->value, " \t", -$wsLength ) === $wsLength )
- {
+ && strspn( $accum->lastNode->value, " \t", -$wsLength ) === $wsLength
+ ) {
$accum->lastNode->value = substr( $accum->lastNode->value, 0, -$wsLength );
}
@@ -404,8 +422,8 @@ class Preprocessor_Hash implements Preprocessor {
$attrEnd = $tagEndPos;
// Find closing tag
if ( preg_match( "/<\/" . preg_quote( $name, '/' ) . "\s*>/i",
- $text, $matches, PREG_OFFSET_CAPTURE, $tagEndPos + 1 ) )
- {
+ $text, $matches, PREG_OFFSET_CAPTURE, $tagEndPos + 1 )
+ ) {
$inner = substr( $text, $tagEndPos + 1, $matches[0][1] - $tagEndPos - 1 );
$i = $matches[0][1] + strlen( $matches[0][0] );
$close = $matches[0][0];
@@ -440,9 +458,7 @@ class Preprocessor_Hash implements Preprocessor {
$extNode->addChild( PPNode_Hash_Tree::newWithText( 'close', $close ) );
}
$accum->addNode( $extNode );
- }
-
- elseif ( $found == 'line-start' ) {
+ } elseif ( $found == 'line-start' ) {
// Is this the start of a heading?
// Line break belongs before the heading element in any case
if ( $fakeLineStart ) {
@@ -454,9 +470,10 @@ class Preprocessor_Hash implements Preprocessor {
$count = strspn( $text, '=', $i, 6 );
if ( $count == 1 && $findEquals ) {
- // DWIM: This looks kind of like a name/value separator
- // Let's let the equals handler have it and break the potential heading
- // This is heuristic, but AFAICT the methods for completely correct disambiguation are very complex.
+ // DWIM: This looks kind of like a name/value separator.
+ // Let's let the equals handler have it and break the potential
+ // heading. This is heuristic, but AFAICT the methods for
+ // completely correct disambiguation are very complex.
} elseif ( $count > 0 ) {
$piece = array(
'open' => "\n",
@@ -474,8 +491,9 @@ class Preprocessor_Hash implements Preprocessor {
// A heading must be open, otherwise \n wouldn't have been in the search list
assert( '$piece->open == "\n"' );
$part = $piece->getCurrentPart();
- // Search back through the input to see if it has a proper close
- // Do this using the reversed string since the other solutions (end anchor, etc.) are inefficient
+ // Search back through the input to see if it has a proper close.
+ // Do this using the reversed string since the other solutions
+ // (end anchor, etc.) are inefficient.
$wsLength = strspn( $revText, " \t", $lengthText - $i );
$searchStart = $i - $wsLength;
if ( isset( $part->commentEnd ) && $searchStart - 1 == $part->commentEnd ) {
@@ -743,9 +761,12 @@ class Preprocessor_Hash implements Preprocessor {
/**
* Stack class to help Preprocessor::preprocessToObj()
* @ingroup Parser
+ * @codingStandardsIgnoreStart
*/
class PPDStack_Hash extends PPDStack {
- function __construct() {
+ // @codingStandardsIgnoreEnd
+
+ public function __construct() {
$this->elementClass = 'PPDStackElement_Hash';
parent::__construct();
$this->rootAccum = new PPDAccum_Hash;
@@ -754,9 +775,12 @@ class PPDStack_Hash extends PPDStack {
/**
* @ingroup Parser
+ * @codingStandardsIgnoreStart
*/
class PPDStackElement_Hash extends PPDStackElement {
- function __construct( $data = array() ) {
+ // @codingStandardsIgnoreENd
+
+ public function __construct( $data = array() ) {
$this->partClass = 'PPDPart_Hash';
parent::__construct( $data );
}
@@ -764,9 +788,10 @@ class PPDStackElement_Hash extends PPDStackElement {
/**
* Get the accumulator that would result if the close is not found.
*
+ * @param int|bool $openingCount
* @return PPDAccum_Hash
*/
- function breakSyntax( $openingCount = false ) {
+ public function breakSyntax( $openingCount = false ) {
if ( $this->open == "\n" ) {
$accum = $this->parts[0]->out;
} else {
@@ -791,9 +816,12 @@ class PPDStackElement_Hash extends PPDStackElement {
/**
* @ingroup Parser
+ * @codingStandardsIgnoreStart
*/
class PPDPart_Hash extends PPDPart {
- function __construct( $out = '' ) {
+ // @codingStandardsIgnoreEnd
+
+ public function __construct( $out = '' ) {
$accum = new PPDAccum_Hash;
if ( $out !== '' ) {
$accum->addLiteral( $out );
@@ -804,18 +832,22 @@ class PPDPart_Hash extends PPDPart {
/**
* @ingroup Parser
+ * @codingStandardsIgnoreStart
*/
class PPDAccum_Hash {
- var $firstNode, $lastNode;
+ // @codingStandardsIgnoreEnd
+
+ public $firstNode, $lastNode;
- function __construct() {
+ public function __construct() {
$this->firstNode = $this->lastNode = false;
}
/**
* Append a string literal
+ * @param string $s
*/
- function addLiteral( $s ) {
+ public function addLiteral( $s ) {
if ( $this->lastNode === false ) {
$this->firstNode = $this->lastNode = new PPNode_Hash_Text( $s );
} elseif ( $this->lastNode instanceof PPNode_Hash_Text ) {
@@ -828,8 +860,9 @@ class PPDAccum_Hash {
/**
* Append a PPNode
+ * @param PPNode $node
*/
- function addNode( PPNode $node ) {
+ public function addNode( PPNode $node ) {
if ( $this->lastNode === false ) {
$this->firstNode = $this->lastNode = $node;
} else {
@@ -840,18 +873,21 @@ class PPDAccum_Hash {
/**
* Append a tree node with text contents
+ * @param string $name
+ * @param string $value
*/
- function addNodeWithText( $name, $value ) {
+ public function addNodeWithText( $name, $value ) {
$node = PPNode_Hash_Tree::newWithText( $name, $value );
$this->addNode( $node );
}
/**
- * Append a PPAccum_Hash
+ * Append a PPDAccum_Hash
* Takes over ownership of the nodes in the source argument. These nodes may
* subsequently be modified, especially nextSibling.
+ * @param PPDAccum_Hash $accum
*/
- function addAccum( $accum ) {
+ public function addAccum( $accum ) {
if ( $accum->lastNode === false ) {
// nothing to add
} elseif ( $this->lastNode === false ) {
@@ -867,62 +903,72 @@ class PPDAccum_Hash {
/**
* An expansion frame, used as a context to expand the result of preprocessToObj()
* @ingroup Parser
+ * @codingStandardsIgnoreStart
*/
class PPFrame_Hash implements PPFrame {
+ // @codingStandardsIgnoreEnd
/**
* @var Parser
*/
- var $parser;
+ public $parser;
/**
* @var Preprocessor
*/
- var $preprocessor;
+ public $preprocessor;
/**
* @var Title
*/
- var $title;
- var $titleCache;
+ public $title;
+ public $titleCache;
/**
* Hashtable listing templates which are disallowed for expansion in this frame,
* having been encountered previously in parent frames.
*/
- var $loopCheckHash;
+ public $loopCheckHash;
/**
* Recursion depth of this frame, top = 0
* Note that this is NOT the same as expansion depth in expand()
*/
- var $depth;
+ public $depth;
+
+ private $volatile = false;
+ private $ttl = null;
+
+ /**
+ * @var array
+ */
+ protected $childExpansionCache;
/**
* Construct a new preprocessor frame.
- * @param $preprocessor Preprocessor: the parent preprocessor
+ * @param Preprocessor $preprocessor The parent preprocessor
*/
- function __construct( $preprocessor ) {
+ public function __construct( $preprocessor ) {
$this->preprocessor = $preprocessor;
$this->parser = $preprocessor->parser;
$this->title = $this->parser->mTitle;
$this->titleCache = array( $this->title ? $this->title->getPrefixedDBkey() : false );
$this->loopCheckHash = array();
$this->depth = 0;
+ $this->childExpansionCache = array();
}
/**
* Create a new child frame
* $args is optionally a multi-root PPNode or array containing the template arguments
*
- * @param array|bool|\PPNode_Hash_Array $args PPNode_Hash_Array|array
- * @param $title Title|bool
- *
+ * @param array|bool|PPNode_Hash_Array $args
+ * @param Title|bool $title
* @param int $indexOffset
* @throws MWException
* @return PPTemplateFrame_Hash
*/
- function newChild( $args = false, $title = false, $indexOffset = 0 ) {
+ public function newChild( $args = false, $title = false, $indexOffset = 0 ) {
$namedArgs = array();
$numberedArgs = array();
if ( $title === false ) {
@@ -954,11 +1000,23 @@ class PPFrame_Hash implements PPFrame {
/**
* @throws MWException
- * @param $root
- * @param $flags int
+ * @param string|int $key
+ * @param string|PPNode $root
+ * @param int $flags
+ * @return string
+ */
+ public function cachedExpand( $key, $root, $flags = 0 ) {
+ // we don't have a parent, so we don't have a cache
+ return $this->expand( $root, $flags );
+ }
+
+ /**
+ * @throws MWException
+ * @param string|PPNode $root
+ * @param int $flags
* @return string
*/
- function expand( $root, $flags = 0 ) {
+ public function expand( $root, $flags = 0 ) {
static $expansionDepth = 0;
if ( is_string( $root ) ) {
return $root;
@@ -1035,7 +1093,11 @@ class PPFrame_Hash implements PPFrame {
# Double-brace expansion
$bits = $contextNode->splitTemplate();
if ( $flags & PPFrame::NO_TEMPLATES ) {
- $newIterator = $this->virtualBracketedImplode( '{{', '|', '}}', $bits['title'], $bits['parts'] );
+ $newIterator = $this->virtualBracketedImplode(
+ '{{', '|', '}}',
+ $bits['title'],
+ $bits['parts']
+ );
} else {
$ret = $this->parser->braceSubstitution( $bits, $this );
if ( isset( $ret['object'] ) ) {
@@ -1048,7 +1110,11 @@ class PPFrame_Hash implements PPFrame {
# Triple-brace expansion
$bits = $contextNode->splitTemplate();
if ( $flags & PPFrame::NO_ARGS ) {
- $newIterator = $this->virtualBracketedImplode( '{{{', '|', '}}}', $bits['title'], $bits['parts'] );
+ $newIterator = $this->virtualBracketedImplode(
+ '{{{', '|', '}}}',
+ $bits['title'],
+ $bits['parts']
+ );
} else {
$ret = $this->parser->argSubstitution( $bits, $this );
if ( isset( $ret['object'] ) ) {
@@ -1062,17 +1128,16 @@ class PPFrame_Hash implements PPFrame {
# Remove it in HTML, pre+remove and STRIP_COMMENTS modes
if ( $this->parser->ot['html']
|| ( $this->parser->ot['pre'] && $this->parser->mOptions->getRemoveComments() )
- || ( $flags & PPFrame::STRIP_COMMENTS ) )
- {
+ || ( $flags & PPFrame::STRIP_COMMENTS )
+ ) {
$out .= '';
- }
- # Add a strip marker in PST mode so that pstPass2() can run some old-fashioned regexes on the result
- # Not in RECOVER_COMMENTS mode (extractSections) though
- elseif ( $this->parser->ot['wiki'] && !( $flags & PPFrame::RECOVER_COMMENTS ) ) {
+ } elseif ( $this->parser->ot['wiki'] && !( $flags & PPFrame::RECOVER_COMMENTS ) ) {
+ # Add a strip marker in PST mode so that pstPass2() can
+ # run some old-fashioned regexes on the result.
+ # Not in RECOVER_COMMENTS mode (extractSections) though.
$out .= $this->parser->insertStripItem( $contextNode->firstChild->value );
- }
- # Recover the literal comment in RECOVER_COMMENTS and pre+no-remove
- else {
+ } else {
+ # Recover the literal comment in RECOVER_COMMENTS and pre+no-remove
$out .= $contextNode->firstChild->value;
}
} elseif ( $contextNode->name == 'ignore' ) {
@@ -1080,7 +1145,9 @@ class PPFrame_Hash implements PPFrame {
# OT_WIKI will only respect <ignore> in substed templates.
# The other output types respect it unless NO_IGNORE is set.
# extractSections() sets NO_IGNORE and so never respects it.
- if ( ( !isset( $this->parent ) && $this->parser->ot['wiki'] ) || ( $flags & PPFrame::NO_IGNORE ) ) {
+ if ( ( !isset( $this->parent ) && $this->parser->ot['wiki'] )
+ || ( $flags & PPFrame::NO_IGNORE )
+ ) {
$out .= $contextNode->firstChild->value;
} else {
//$out .= '';
@@ -1088,7 +1155,23 @@ class PPFrame_Hash implements PPFrame {
} elseif ( $contextNode->name == 'ext' ) {
# Extension tag
$bits = $contextNode->splitExt() + array( 'attr' => null, 'inner' => null, 'close' => null );
- $out .= $this->parser->extensionSubstitution( $bits, $this );
+ if ( $flags & PPFrame::NO_TAGS ) {
+ $s = '<' . $bits['name']->firstChild->value;
+ if ( $bits['attr'] ) {
+ $s .= $bits['attr']->firstChild->value;
+ }
+ if ( $bits['inner'] ) {
+ $s .= '>' . $bits['inner']->firstChild->value;
+ if ( $bits['close'] ) {
+ $s .= $bits['close']->firstChild->value;
+ }
+ } else {
+ $s .= '/>';
+ }
+ $out .= $s;
+ } else {
+ $out .= $this->parser->extensionSubstitution( $bits, $this );
+ }
} elseif ( $contextNode->name == 'h' ) {
# Heading
if ( $this->parser->ot['html'] ) {
@@ -1139,11 +1222,12 @@ class PPFrame_Hash implements PPFrame {
}
/**
- * @param $sep
- * @param $flags
+ * @param string $sep
+ * @param int $flags
+ * @param string|PPNode $args,...
* @return string
*/
- function implodeWithFlags( $sep, $flags /*, ... */ ) {
+ public function implodeWithFlags( $sep, $flags /*, ... */ ) {
$args = array_slice( func_get_args(), 2 );
$first = true;
@@ -1170,9 +1254,11 @@ class PPFrame_Hash implements PPFrame {
/**
* Implode with no flags specified
* This previously called implodeWithFlags but has now been inlined to reduce stack depth
+ * @param string $sep
+ * @param string|PPNode $args,...
* @return string
*/
- function implode( $sep /*, ... */ ) {
+ public function implode( $sep /*, ... */ ) {
$args = array_slice( func_get_args(), 1 );
$first = true;
@@ -1200,9 +1286,11 @@ class PPFrame_Hash implements PPFrame {
* Makes an object that, when expand()ed, will be the same as one obtained
* with implode()
*
+ * @param string $sep
+ * @param string|PPNode $args,...
* @return PPNode_Hash_Array
*/
- function virtualImplode( $sep /*, ... */ ) {
+ public function virtualImplode( $sep /*, ... */ ) {
$args = array_slice( func_get_args(), 1 );
$out = array();
$first = true;
@@ -1229,9 +1317,13 @@ class PPFrame_Hash implements PPFrame {
/**
* Virtual implode with brackets
*
+ * @param string $start
+ * @param string $sep
+ * @param string $end
+ * @param string|PPNode $args,...
* @return PPNode_Hash_Array
*/
- function virtualBracketedImplode( $start, $sep, $end /*, ... */ ) {
+ public function virtualBracketedImplode( $start, $sep, $end /*, ... */ ) {
$args = array_slice( func_get_args(), 3 );
$out = array( $start );
$first = true;
@@ -1256,15 +1348,15 @@ class PPFrame_Hash implements PPFrame {
return new PPNode_Hash_Array( $out );
}
- function __toString() {
+ public function __toString() {
return 'frame{}';
}
/**
- * @param $level bool
- * @return array|bool|String
+ * @param bool $level
+ * @return array|bool|string
*/
- function getPDBK( $level = false ) {
+ public function getPDBK( $level = false ) {
if ( $level === false ) {
return $this->title->getPrefixedDBkey();
} else {
@@ -1275,21 +1367,21 @@ class PPFrame_Hash implements PPFrame {
/**
* @return array
*/
- function getArguments() {
+ public function getArguments() {
return array();
}
/**
* @return array
*/
- function getNumberedArguments() {
+ public function getNumberedArguments() {
return array();
}
/**
* @return array
*/
- function getNamedArguments() {
+ public function getNamedArguments() {
return array();
}
@@ -1298,26 +1390,26 @@ class PPFrame_Hash implements PPFrame {
*
* @return bool
*/
- function isEmpty() {
+ public function isEmpty() {
return true;
}
/**
- * @param $name
+ * @param string $name
* @return bool
*/
- function getArgument( $name ) {
+ public function getArgument( $name ) {
return false;
}
/**
* Returns true if the infinite loop check is OK, false if a loop is detected
*
- * @param $title Title
+ * @param Title $title
*
* @return bool
*/
- function loopCheck( $title ) {
+ public function loopCheck( $title ) {
return !isset( $this->loopCheckHash[$title->getPrefixedDBkey()] );
}
@@ -1326,7 +1418,7 @@ class PPFrame_Hash implements PPFrame {
*
* @return bool
*/
- function isTemplate() {
+ public function isTemplate() {
return false;
}
@@ -1335,27 +1427,70 @@ class PPFrame_Hash implements PPFrame {
*
* @return Title
*/
- function getTitle() {
+ public function getTitle() {
return $this->title;
}
+
+ /**
+ * Set the volatile flag
+ *
+ * @param bool $flag
+ */
+ public function setVolatile( $flag = true ) {
+ $this->volatile = $flag;
+ }
+
+ /**
+ * Get the volatile flag
+ *
+ * @return bool
+ */
+ public function isVolatile() {
+ return $this->volatile;
+ }
+
+ /**
+ * Set the TTL
+ *
+ * @param int $ttl
+ */
+ public function setTTL( $ttl ) {
+ if ( $ttl !== null && ( $this->ttl === null || $ttl < $this->ttl ) ) {
+ $this->ttl = $ttl;
+ }
+ }
+
+ /**
+ * Get the TTL
+ *
+ * @return int|null
+ */
+ public function getTTL() {
+ return $this->ttl;
+ }
}
/**
* Expansion frame with template arguments
* @ingroup Parser
+ * @codingStandardsIgnoreStart
*/
class PPTemplateFrame_Hash extends PPFrame_Hash {
- var $numberedArgs, $namedArgs, $parent;
- var $numberedExpansionCache, $namedExpansionCache;
+ // @codingStandardsIgnoreEnd
+
+ public $numberedArgs, $namedArgs, $parent;
+ public $numberedExpansionCache, $namedExpansionCache;
/**
- * @param $preprocessor
- * @param $parent
- * @param $numberedArgs array
- * @param $namedArgs array
- * @param $title Title
+ * @param Preprocessor $preprocessor
+ * @param bool|PPFrame $parent
+ * @param array $numberedArgs
+ * @param array $namedArgs
+ * @param bool|Title $title
*/
- function __construct( $preprocessor, $parent = false, $numberedArgs = array(), $namedArgs = array(), $title = false ) {
+ public function __construct( $preprocessor, $parent = false, $numberedArgs = array(),
+ $namedArgs = array(), $title = false
+ ) {
parent::__construct( $preprocessor );
$this->parent = $parent;
@@ -1373,7 +1508,7 @@ class PPTemplateFrame_Hash extends PPFrame_Hash {
$this->numberedExpansionCache = $this->namedExpansionCache = array();
}
- function __toString() {
+ public function __toString() {
$s = 'tplframe{';
$first = true;
$args = $this->numberedArgs + $this->namedArgs;
@@ -1389,19 +1524,38 @@ class PPTemplateFrame_Hash extends PPFrame_Hash {
$s .= '}';
return $s;
}
+
+ /**
+ * @throws MWException
+ * @param string|int $key
+ * @param string|PPNode $root
+ * @param int $flags
+ * @return string
+ */
+ public function cachedExpand( $key, $root, $flags = 0 ) {
+ if ( isset( $this->parent->childExpansionCache[$key] ) ) {
+ return $this->parent->childExpansionCache[$key];
+ }
+ $retval = $this->expand( $root, $flags );
+ if ( !$this->isVolatile() ) {
+ $this->parent->childExpansionCache[$key] = $retval;
+ }
+ return $retval;
+ }
+
/**
* Returns true if there are no arguments in this frame
*
* @return bool
*/
- function isEmpty() {
+ public function isEmpty() {
return !count( $this->numberedArgs ) && !count( $this->namedArgs );
}
/**
* @return array
*/
- function getArguments() {
+ public function getArguments() {
$arguments = array();
foreach ( array_merge(
array_keys( $this->numberedArgs ),
@@ -1414,7 +1568,7 @@ class PPTemplateFrame_Hash extends PPFrame_Hash {
/**
* @return array
*/
- function getNumberedArguments() {
+ public function getNumberedArguments() {
$arguments = array();
foreach ( array_keys( $this->numberedArgs ) as $key ) {
$arguments[$key] = $this->getArgument( $key );
@@ -1425,7 +1579,7 @@ class PPTemplateFrame_Hash extends PPFrame_Hash {
/**
* @return array
*/
- function getNamedArguments() {
+ public function getNamedArguments() {
$arguments = array();
foreach ( array_keys( $this->namedArgs ) as $key ) {
$arguments[$key] = $this->getArgument( $key );
@@ -1434,25 +1588,28 @@ class PPTemplateFrame_Hash extends PPFrame_Hash {
}
/**
- * @param $index
+ * @param int $index
* @return array|bool
*/
- function getNumberedArgument( $index ) {
+ public function getNumberedArgument( $index ) {
if ( !isset( $this->numberedArgs[$index] ) ) {
return false;
}
if ( !isset( $this->numberedExpansionCache[$index] ) ) {
# No trimming for unnamed arguments
- $this->numberedExpansionCache[$index] = $this->parent->expand( $this->numberedArgs[$index], PPFrame::STRIP_COMMENTS );
+ $this->numberedExpansionCache[$index] = $this->parent->expand(
+ $this->numberedArgs[$index],
+ PPFrame::STRIP_COMMENTS
+ );
}
return $this->numberedExpansionCache[$index];
}
/**
- * @param $name
+ * @param string $name
* @return bool
*/
- function getNamedArgument( $name ) {
+ public function getNamedArgument( $name ) {
if ( !isset( $this->namedArgs[$name] ) ) {
return false;
}
@@ -1465,10 +1622,10 @@ class PPTemplateFrame_Hash extends PPFrame_Hash {
}
/**
- * @param $name
+ * @param string $name
* @return array|bool
*/
- function getArgument( $name ) {
+ public function getArgument( $name ) {
$text = $this->getNumberedArgument( $name );
if ( $text === false ) {
$text = $this->getNamedArgument( $name );
@@ -1481,24 +1638,37 @@ class PPTemplateFrame_Hash extends PPFrame_Hash {
*
* @return bool
*/
- function isTemplate() {
+ public function isTemplate() {
return true;
}
+
+ public function setVolatile( $flag = true ) {
+ parent::setVolatile( $flag );
+ $this->parent->setVolatile( $flag );
+ }
+
+ public function setTTL( $ttl ) {
+ parent::setTTL( $ttl );
+ $this->parent->setTTL( $ttl );
+ }
}
/**
* Expansion frame with custom arguments
* @ingroup Parser
+ * @codingStandardsIgnoreStart
*/
class PPCustomFrame_Hash extends PPFrame_Hash {
- var $args;
+ // @codingStandardsIgnoreEnd
- function __construct( $preprocessor, $args ) {
+ public $args;
+
+ public function __construct( $preprocessor, $args ) {
parent::__construct( $preprocessor );
$this->args = $args;
}
- function __toString() {
+ public function __toString() {
$s = 'cstmframe{';
$first = true;
foreach ( $this->args as $name => $value ) {
@@ -1517,38 +1687,41 @@ class PPCustomFrame_Hash extends PPFrame_Hash {
/**
* @return bool
*/
- function isEmpty() {
+ public function isEmpty() {
return !count( $this->args );
}
/**
- * @param $index
+ * @param int $index
* @return bool
*/
- function getArgument( $index ) {
+ public function getArgument( $index ) {
if ( !isset( $this->args[$index] ) ) {
return false;
}
return $this->args[$index];
}
- function getArguments() {
+ public function getArguments() {
return $this->args;
}
}
/**
* @ingroup Parser
+ * @codingStandardsIgnoreStart
*/
class PPNode_Hash_Tree implements PPNode {
- var $name, $firstChild, $lastChild, $nextSibling;
+ // @codingStandardsIgnoreEnd
+
+ public $name, $firstChild, $lastChild, $nextSibling;
- function __construct( $name ) {
+ public function __construct( $name ) {
$this->name = $name;
$this->firstChild = $this->lastChild = $this->nextSibling = false;
}
- function __toString() {
+ public function __toString() {
$inner = '';
$attribs = '';
for ( $node = $this->firstChild; $node; $node = $node->nextSibling ) {
@@ -1566,17 +1739,17 @@ class PPNode_Hash_Tree implements PPNode {
}
/**
- * @param $name
- * @param $text
+ * @param string $name
+ * @param string $text
* @return PPNode_Hash_Tree
*/
- static function newWithText( $name, $text ) {
+ public static function newWithText( $name, $text ) {
$obj = new self( $name );
$obj->addChild( new PPNode_Hash_Text( $text ) );
return $obj;
}
- function addChild( $node ) {
+ public function addChild( $node ) {
if ( $this->lastChild === false ) {
$this->firstChild = $this->lastChild = $node;
} else {
@@ -1588,7 +1761,7 @@ class PPNode_Hash_Tree implements PPNode {
/**
* @return PPNode_Hash_Array
*/
- function getChildren() {
+ public function getChildren() {
$children = array();
for ( $child = $this->firstChild; $child; $child = $child->nextSibling ) {
$children[] = $child;
@@ -1596,15 +1769,15 @@ class PPNode_Hash_Tree implements PPNode {
return new PPNode_Hash_Array( $children );
}
- function getFirstChild() {
+ public function getFirstChild() {
return $this->firstChild;
}
- function getNextSibling() {
+ public function getNextSibling() {
return $this->nextSibling;
}
- function getChildrenOfType( $name ) {
+ public function getChildrenOfType( $name ) {
$children = array();
for ( $child = $this->firstChild; $child; $child = $child->nextSibling ) {
if ( isset( $child->name ) && $child->name === $name ) {
@@ -1617,22 +1790,22 @@ class PPNode_Hash_Tree implements PPNode {
/**
* @return bool
*/
- function getLength() {
+ public function getLength() {
return false;
}
/**
- * @param $i
+ * @param int $i
* @return bool
*/
- function item( $i ) {
+ public function item( $i ) {
return false;
}
/**
* @return string
*/
- function getName() {
+ public function getName() {
return $this->name;
}
@@ -1645,7 +1818,7 @@ class PPNode_Hash_Tree implements PPNode {
* @throws MWException
* @return array
*/
- function splitArg() {
+ public function splitArg() {
$bits = array();
for ( $child = $this->firstChild; $child; $child = $child->nextSibling ) {
if ( !isset( $child->name ) ) {
@@ -1654,8 +1827,8 @@ class PPNode_Hash_Tree implements PPNode {
if ( $child->name === 'name' ) {
$bits['name'] = $child;
if ( $child->firstChild instanceof PPNode_Hash_Attr
- && $child->firstChild->name === 'index' )
- {
+ && $child->firstChild->name === 'index'
+ ) {
$bits['index'] = $child->firstChild->value;
}
} elseif ( $child->name === 'value' ) {
@@ -1679,7 +1852,7 @@ class PPNode_Hash_Tree implements PPNode {
* @throws MWException
* @return array
*/
- function splitExt() {
+ public function splitExt() {
$bits = array();
for ( $child = $this->firstChild; $child; $child = $child->nextSibling ) {
if ( !isset( $child->name ) ) {
@@ -1707,7 +1880,7 @@ class PPNode_Hash_Tree implements PPNode {
* @throws MWException
* @return array
*/
- function splitHeading() {
+ public function splitHeading() {
if ( $this->name !== 'h' ) {
throw new MWException( 'Invalid h node passed to ' . __METHOD__ );
}
@@ -1734,7 +1907,7 @@ class PPNode_Hash_Tree implements PPNode {
* @throws MWException
* @return array
*/
- function splitTemplate() {
+ public function splitTemplate() {
$parts = array();
$bits = array( 'lineStart' => '' );
for ( $child = $this->firstChild; $child; $child = $child->nextSibling ) {
@@ -1761,101 +1934,178 @@ class PPNode_Hash_Tree implements PPNode {
/**
* @ingroup Parser
+ * @codingStandardsIgnoreStart
*/
class PPNode_Hash_Text implements PPNode {
- var $value, $nextSibling;
+ // @codingStandardsIgnoreEnd
- function __construct( $value ) {
+ public $value, $nextSibling;
+
+ public function __construct( $value ) {
if ( is_object( $value ) ) {
throw new MWException( __CLASS__ . ' given object instead of string' );
}
$this->value = $value;
}
- function __toString() {
+ public function __toString() {
return htmlspecialchars( $this->value );
}
- function getNextSibling() {
+ public function getNextSibling() {
return $this->nextSibling;
}
- function getChildren() { return false; }
- function getFirstChild() { return false; }
- function getChildrenOfType( $name ) { return false; }
- function getLength() { return false; }
- function item( $i ) { return false; }
- function getName() { return '#text'; }
- function splitArg() { throw new MWException( __METHOD__ . ': not supported' ); }
- function splitExt() { throw new MWException( __METHOD__ . ': not supported' ); }
- function splitHeading() { throw new MWException( __METHOD__ . ': not supported' ); }
+ public function getChildren() {
+ return false;
+ }
+
+ public function getFirstChild() {
+ return false;
+ }
+
+ public function getChildrenOfType( $name ) {
+ return false;
+ }
+
+ public function getLength() {
+ return false;
+ }
+
+ public function item( $i ) {
+ return false;
+ }
+
+ public function getName() {
+ return '#text';
+ }
+
+ public function splitArg() {
+ throw new MWException( __METHOD__ . ': not supported' );
+ }
+
+ public function splitExt() {
+ throw new MWException( __METHOD__ . ': not supported' );
+ }
+
+ public function splitHeading() {
+ throw new MWException( __METHOD__ . ': not supported' );
+ }
}
/**
* @ingroup Parser
+ * @codingStandardsIgnoreStart
*/
class PPNode_Hash_Array implements PPNode {
- var $value, $nextSibling;
+ // @codingStandardsIgnoreEnd
+
+ public $value, $nextSibling;
- function __construct( $value ) {
+ public function __construct( $value ) {
$this->value = $value;
}
- function __toString() {
+ public function __toString() {
return var_export( $this, true );
}
- function getLength() {
+ public function getLength() {
return count( $this->value );
}
- function item( $i ) {
+ public function item( $i ) {
return $this->value[$i];
}
- function getName() { return '#nodelist'; }
+ public function getName() {
+ return '#nodelist';
+ }
- function getNextSibling() {
+ public function getNextSibling() {
return $this->nextSibling;
}
- function getChildren() { return false; }
- function getFirstChild() { return false; }
- function getChildrenOfType( $name ) { return false; }
- function splitArg() { throw new MWException( __METHOD__ . ': not supported' ); }
- function splitExt() { throw new MWException( __METHOD__ . ': not supported' ); }
- function splitHeading() { throw new MWException( __METHOD__ . ': not supported' ); }
+ public function getChildren() {
+ return false;
+ }
+
+ public function getFirstChild() {
+ return false;
+ }
+
+ public function getChildrenOfType( $name ) {
+ return false;
+ }
+
+ public function splitArg() {
+ throw new MWException( __METHOD__ . ': not supported' );
+ }
+
+ public function splitExt() {
+ throw new MWException( __METHOD__ . ': not supported' );
+ }
+
+ public function splitHeading() {
+ throw new MWException( __METHOD__ . ': not supported' );
+ }
}
/**
* @ingroup Parser
+ * @codingStandardsIgnoreStart
*/
class PPNode_Hash_Attr implements PPNode {
- var $name, $value, $nextSibling;
+ // @codingStandardsIgnoreEnd
+
+ public $name, $value, $nextSibling;
- function __construct( $name, $value ) {
+ public function __construct( $name, $value ) {
$this->name = $name;
$this->value = $value;
}
- function __toString() {
+ public function __toString() {
return "<@{$this->name}>" . htmlspecialchars( $this->value ) . "</@{$this->name}>";
}
- function getName() {
+ public function getName() {
return $this->name;
}
- function getNextSibling() {
+ public function getNextSibling() {
return $this->nextSibling;
}
- function getChildren() { return false; }
- function getFirstChild() { return false; }
- function getChildrenOfType( $name ) { return false; }
- function getLength() { return false; }
- function item( $i ) { return false; }
- function splitArg() { throw new MWException( __METHOD__ . ': not supported' ); }
- function splitExt() { throw new MWException( __METHOD__ . ': not supported' ); }
- function splitHeading() { throw new MWException( __METHOD__ . ': not supported' ); }
+ public function getChildren() {
+ return false;
+ }
+
+ public function getFirstChild() {
+ return false;
+ }
+
+ public function getChildrenOfType( $name ) {
+ return false;
+ }
+
+ public function getLength() {
+ return false;
+ }
+
+ public function item( $i ) {
+ return false;
+ }
+
+ public function splitArg() {
+ throw new MWException( __METHOD__ . ': not supported' );
+ }
+
+ public function splitExt() {
+ throw new MWException( __METHOD__ . ': not supported' );
+ }
+
+ public function splitHeading() {
+ throw new MWException( __METHOD__ . ': not supported' );
+ }
}
diff --git a/includes/parser/StripState.php b/includes/parser/StripState.php
index 5f3f18ea..5d1743e6 100644
--- a/includes/parser/StripState.php
+++ b/includes/parser/StripState.php
@@ -37,9 +37,9 @@ class StripState {
const UNSTRIP_RECURSION_LIMIT = 20;
/**
- * @param $prefix string
+ * @param string $prefix
*/
- function __construct( $prefix ) {
+ public function __construct( $prefix ) {
$this->prefix = $prefix;
$this->data = array(
'nowiki' => array(),
@@ -51,26 +51,26 @@ class StripState {
/**
* Add a nowiki strip item
- * @param $marker
- * @param $value
+ * @param string $marker
+ * @param string $value
*/
- function addNoWiki( $marker, $value ) {
+ public function addNoWiki( $marker, $value ) {
$this->addItem( 'nowiki', $marker, $value );
}
/**
- * @param $marker
- * @param $value
+ * @param string $marker
+ * @param string $value
*/
- function addGeneral( $marker, $value ) {
+ public function addGeneral( $marker, $value ) {
$this->addItem( 'general', $marker, $value );
}
/**
* @throws MWException
- * @param $type
- * @param $marker
- * @param $value
+ * @param string $type
+ * @param string $marker
+ * @param string $value
*/
protected function addItem( $type, $marker, $value ) {
if ( !preg_match( $this->regex, $marker, $m ) ) {
@@ -81,34 +81,34 @@ class StripState {
}
/**
- * @param $text
+ * @param string $text
* @return mixed
*/
- function unstripGeneral( $text ) {
+ public function unstripGeneral( $text ) {
return $this->unstripType( 'general', $text );
}
/**
- * @param $text
+ * @param string $text
* @return mixed
*/
- function unstripNoWiki( $text ) {
+ public function unstripNoWiki( $text ) {
return $this->unstripType( 'nowiki', $text );
}
/**
- * @param $text
+ * @param string $text
* @return mixed
*/
- function unstripBoth( $text ) {
+ public function unstripBoth( $text ) {
$text = $this->unstripType( 'general', $text );
$text = $this->unstripType( 'nowiki', $text );
return $text;
}
/**
- * @param $type
- * @param $text
+ * @param string $type
+ * @param string $text
* @return mixed
*/
protected function unstripType( $type, $text ) {
@@ -127,7 +127,7 @@ class StripState {
}
/**
- * @param $m array
+ * @param array $m
* @return array
*/
protected function unstripCallback( $m ) {
@@ -159,11 +159,11 @@ class StripState {
* Get a StripState object which is sufficient to unstrip the given text.
* It will contain the minimum subset of strip items necessary.
*
- * @param $text string
+ * @param string $text
*
* @return StripState
*/
- function getSubState( $text ) {
+ public function getSubState( $text ) {
$subState = new StripState( $this->prefix );
$pos = 0;
while ( true ) {
@@ -195,11 +195,11 @@ class StripState {
* will not be preserved. The strings in the $texts array will have their
* strip markers rewritten, the resulting array of strings will be returned.
*
- * @param $otherState StripState
- * @param $texts Array
- * @return Array
+ * @param StripState $otherState
+ * @param array $texts
+ * @return array
*/
- function merge( $otherState, $texts ) {
+ public function merge( $otherState, $texts ) {
$mergePrefix = Parser::getRandomString();
foreach ( $otherState->data as $type => $items ) {
@@ -215,7 +215,7 @@ class StripState {
}
/**
- * @param $m
+ * @param array $m
* @return string
*/
protected function mergeCallback( $m ) {
@@ -226,10 +226,10 @@ class StripState {
/**
* Remove any strip markers found in the given text.
*
- * @param $text Input string
+ * @param string $text Input string
* @return string
*/
- function killMarkers( $text ) {
+ public function killMarkers( $text ) {
return preg_replace( $this->regex, '', $text );
}
}