diff options
Diffstat (limited to 'includes/parser/ParserOutput.php')
-rw-r--r-- | includes/parser/ParserOutput.php | 208 |
1 files changed, 177 insertions, 31 deletions
diff --git a/includes/parser/ParserOutput.php b/includes/parser/ParserOutput.php index 41b4a385..db649f11 100644 --- a/includes/parser/ParserOutput.php +++ b/includes/parser/ParserOutput.php @@ -50,7 +50,8 @@ class ParserOutput extends CacheTime { $mTimestamp; # Timestamp of the revision 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 instances of SecondaryDataObject(), used to cause some information extracted from the page in a custom place. + private $mSecondaryDataUpdates = array(); # List of DataUpdate, used to save info from the page somewhere else. + private $mExtensionData = array(); # extra data used by extensions const EDITSECTION_REGEX = '#<(?:mw:)?editsection page="(.*?)" section="(.*?)"(?:/>|>(.*?)(</(?:mw:)?editsection>))#'; @@ -75,18 +76,20 @@ class ParserOutput extends CacheTime { /** * 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, + 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."); + if ( !is_object( $args[0] ) ) { + throw new MWException( "Bad parser output text." ); } $args[] = $wgLang->getCode(); $skin = $wgOut->getSkin(); @@ -150,11 +153,35 @@ class ParserOutput extends CacheTime { 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 + * @return bool + */ + 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?:)?' : '' ) . + preg_quote( $internal, '/' ) . + # check for query/path/anchor or end of link in each case + '(?:[\?\/\#]|$)/i', + $url + ); + } + function addExternalLink( $url ) { # We don't register links pointing to our own server, unless... :-) global $wgServer, $wgRegisterInternalExternals; - if( $wgRegisterInternalExternals or stripos($url,$wgServer.'/')!==0) + + $registerExternalLink = true; + if( !$wgRegisterInternalExternals ) { + $registerExternalLink = !self::isLinkInternal( $wgServer, $url ); + } + if( $registerExternalLink ) { $this->mExternalLinks[$url] = 1; + } } /** @@ -163,7 +190,7 @@ class ParserOutput extends CacheTime { * @param $title Title object * @param $id Mixed: optional known page_id so we can skip the lookup */ - function addLink( $title, $id = null ) { + function addLink( Title $title, $id = null ) { if ( $title->isExternal() ) { // Don't record interwikis in pagelinks $this->addInterwikiLink( $title ); @@ -193,9 +220,9 @@ class ParserOutput extends CacheTime { /** * Register a file dependency for this output - * @param $name string Title dbKey - * @param $timestamp string MW timestamp of file creation (or false if non-existing) - * @param $sha1 string base 36 SHA-1 of file (or false if non-existing) + * @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) * @return void */ function addImage( $name, $timestamp = null, $sha1 = null ) { @@ -234,7 +261,7 @@ class ParserOutput extends CacheTime { if( $prefix == '' ) { throw new MWException( 'Non-interwiki link passed, internal parser error.' ); } - if (!isset($this->mInterwikiLinks[$prefix])) { + if ( !isset( $this->mInterwikiLinks[$prefix] ) ) { $this->mInterwikiLinks[$prefix] = array(); } $this->mInterwikiLinks[$prefix][$title->getDBkey()] = 1; @@ -288,7 +315,7 @@ class ParserOutput extends CacheTime { * -- this is assumed to have been validated * (check equal normalisation, etc.) * - * @param $text String: desired title text + * @param string $text desired title text */ public function setDisplayTitle( $text ) { $this->setTitleText( $text ); @@ -320,13 +347,67 @@ class ParserOutput extends CacheTime { } /** - * Set a property to be cached in the DB + * Set a property to be stored in the page_props database table. + * + * page_props is a key value store indexed by the page ID. This allows + * the parser to set a property on a page which can then be quickly + * retrieved given the page ID or via a DB join when given the page + * title. + * + * setProperty() is thus used to propagate properties from the parsed + * page to request contexts other than a page view of the currently parsed + * article. + * + * Some applications examples: + * + * * To implement hidden categories, hiding pages from category listings + * by storing a property. + * + * * Overriding the displayed article title. + * @see ParserOutput::setDisplayTitle() + * + * * To implement image tagging, for example displaying an icon on an + * image thumbnail to indicate that it is listed for deletion on + * 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 + * 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 + * 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 + * parser which is used by an OutputPageParserOutput hook, you have to + * associate the extension data directly with the ParserOutput object. + * Since MediaWiki 1.21, you can use setExtensionData() to do this: + * + * @par Example: + * @code + * $parser->getOutput()->setExtensionData( 'my_ext_foo', '...' ); + * @endcode + * + * And then later, in OutputPageParserOutput or similar: + * + * @par Example: + * @code + * $output->getExtensionData( 'my_ext_foo' ); + * @endcode + * + * In MediaWiki 1.20 and older, you have to use a custom member variable + * within the ParserOutput object: + * + * @par Example: + * @code + * $parser->getOutput()->my_ext_foo = '...'; + * @endcode + * */ public function setProperty( $name, $value ) { $this->mProperties[$name] = $value; } - public function getProperty( $name ){ + public function getProperty( $name ) { return isset( $this->mProperties[$name] ) ? $this->mProperties[$name] : false; } @@ -337,26 +418,25 @@ class ParserOutput extends CacheTime { return $this->mProperties; } - /** * Returns the options from its ParserOptions which have been taken * into account to produce this output or false if not available. * @return mixed Array */ - public function getUsedOptions() { + public function getUsedOptions() { if ( !isset( $this->mAccessedOptions ) ) { return array(); } return array_keys( $this->mAccessedOptions ); - } + } - /** - * Callback passed by the Parser to the ParserOptions to keep track of which options are used. - * @access private - */ - function recordOption( $option ) { - $this->mAccessedOptions[$option] = true; - } + /** + * Callback passed by the Parser to the ParserOptions to keep track of which options are used. + * @access private + */ + 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 @@ -375,9 +455,13 @@ 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. + * * @since 1.20 * - * @param $title Title of the page we're updating. If not given, a title object will be created based on $this->getTitleText() + * @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? * * @return Array. An array of instances of DataUpdate @@ -389,13 +473,75 @@ class ParserOutput extends CacheTime { $linksUpdate = new LinksUpdate( $title, $this, $recursive ); - if ( $this->mSecondaryDataUpdates === array() ) { - return array( $linksUpdate ); + return array_merge( $this->mSecondaryDataUpdates, array( $linksUpdate ) ); + } + + /** + * Attaches arbitrary data to this ParserObject. This can be used to store some information in + * the ParserOutput object for later use during page output. The data will be cached along with + * the ParserOutput object, but unlike data set using setProperty(), it is not recorded in the + * database. + * + * This method is provided to overcome the unsafe practice of attaching extra information to a + * ParserObject by directly assigning member variables. + * + * To use setExtensionData() to pass extension information from a hook inside the parser to a + * hook in the page output, use this in the parser hook: + * + * @par Example: + * @code + * $parser->getOutput()->setExtensionData( 'my_ext_foo', '...' ); + * @endcode + * + * And then later, in OutputPageParserOutput or similar: + * + * @par Example: + * @code + * $output->getExtensionData( 'my_ext_foo' ); + * @endcode + * + * In MediaWiki 1.20 and older, you have to use a custom member variable + * within the ParserOutput object: + * + * @par Example: + * @code + * $parser->getOutput()->my_ext_foo = '...'; + * @endcode + * + * @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. + * + * @param mixed $value The value to set. Setting a value to null is equivalent to removing + * the value. + */ + public function setExtensionData( $key, $value ) { + if ( $value === null ) { + unset( $this->mExtensionData[$key] ); } else { - $updates = array_merge( $this->mSecondaryDataUpdates, array( $linksUpdate ) ); + $this->mExtensionData[$key] = $value; } + } - return $updates; - } + /** + * Gets extensions data previously attached to this ParserOutput using setExtensionData(). + * Typically, such data would be set while parsing the page, e.g. by a parser function. + * + * @since 1.21 + * + * @param string $key The key to look up. + * + * @return mixed The value previously set for the given key using setExtensionData( $key ), + * or null if no value was set for this key. + */ + public function getExtensionData( $key ) { + if ( isset( $this->mExtensionData[$key] ) ) { + return $this->mExtensionData[$key]; + } + + return null; + } } |